2024-06-22 14:57:09 +01:00
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
2024-03-12 18:34:05 +00:00
if ( localStorage . getItem ( "DONOTSHARE-secretkey" ) === null ) {
2024-04-28 23:48:03 +01:00
window . location . replace ( "/login" )
2024-03-12 18:34:05 +00:00
document . body . innerHTML = "Redirecting..."
throw new Error ( ) ;
}
if ( localStorage . getItem ( "DONOTSHARE-password" ) === null ) {
2024-04-28 23:48:03 +01:00
window . location . replace ( "/login" )
2024-03-12 18:34:05 +00:00
document . body . innerHTML = "Redirecting..."
throw new Error ( ) ;
}
let remote = localStorage . getItem ( "homeserverURL" )
if ( remote == null ) {
localStorage . setItem ( "homeserverURL" , "https://notes.hectabit.org" )
remote = "https://notes.hectabit.org"
}
function formatBytes ( a , b = 2 ) { if ( ! + a ) return "0 Bytes" ; const c = 0 > b ? 0 : b , d = Math . floor ( Math . log ( a ) / Math . log ( 1000 ) ) ; return ` ${ parseFloat ( ( a / Math . pow ( 1000 , d ) ) . toFixed ( c ) ) } ${ [ "Bytes" , "KB" , "MB" , "GB" , "TB" , "PB" , "EB" , "ZB" , "YB" ] [ d ] } ` }
let secretkey = localStorage . getItem ( "DONOTSHARE-secretkey" )
let password = localStorage . getItem ( "DONOTSHARE-password" )
2024-04-24 20:25:23 +01:00
let currentFontSize = 16
2024-03-12 18:34:05 +00:00
2024-05-20 20:24:43 +01:00
let backButton = document . getElementById ( "backButton" )
2024-03-12 18:34:05 +00:00
let usernameBox = document . getElementById ( "usernameBox" )
let optionsCoverDiv = document . getElementById ( "optionsCoverDiv" )
let optionsDiv = document . getElementById ( "optionsDiv" )
let errorDiv = document . getElementById ( "errorDiv" )
2024-07-05 22:46:53 +01:00
let uploadThing = document . getElementById ( "uploadThing" )
let browseButton = document . getElementById ( "browseButton" )
2024-03-12 18:34:05 +00:00
let errorMessageThing = document . getElementById ( "errorMessageThing" )
let closeErrorButton = document . getElementById ( "closeErrorButton" )
let cancelErrorButton = document . getElementById ( "cancelErrorButton" )
let errorInput = document . getElementById ( "errorInput" )
let exitThing = document . getElementById ( "exitThing" )
2024-06-27 17:57:05 +01:00
let exitImportThing = document . getElementById ( "exitImportThing" )
2024-03-12 18:34:05 +00:00
let exitSessionsThing = document . getElementById ( "exitSessionsThing" )
let sessionManagerButton = document . getElementById ( "sessionManagerButton" )
2024-05-20 20:24:43 +01:00
let importNotesButton = document . getElementById ( "importNotesButton" )
2024-03-12 18:34:05 +00:00
let sessionManagerDiv = document . getElementById ( "sessionManagerDiv" )
2024-05-20 20:24:43 +01:00
let importNotesDiv = document . getElementById ( "importDiv" )
2024-03-12 18:34:05 +00:00
let sessionDiv = document . getElementById ( "sessionDiv" )
let deleteMyAccountButton = document . getElementById ( "deleteMyAccountButton" )
2024-06-27 17:57:05 +01:00
let changePasswordButton = document . getElementById ( "changePasswordButton" )
2024-03-12 18:34:05 +00:00
let storageThing = document . getElementById ( "storageThing" )
let storageProgressThing = document . getElementById ( "storageProgressThing" )
let usernameThing = document . getElementById ( "usernameThing" )
let logOutButton = document . getElementById ( "logOutButton" )
let notesBar = document . getElementById ( "notesBar" )
2024-06-25 19:43:24 +01:00
let topBar = document . getElementById ( "topBar" )
2024-03-12 18:34:05 +00:00
let notesDiv = document . getElementById ( "notesDiv" )
let newNote = document . getElementById ( "newNote" )
2024-05-20 20:24:43 +01:00
let noteBoxDiv = document . getElementById ( "noteBoxDiv" )
2024-07-02 18:13:28 +01:00
let pellAttacher = document . getElementById ( "noteBox" )
2024-03-12 18:34:05 +00:00
let loadingStuff = document . getElementById ( "loadingStuff" )
let exportNotesButton = document . getElementById ( "exportNotesButton" )
2024-04-28 23:48:03 +01:00
let textSizeBox = document . getElementById ( 'textSizeBox' ) ;
let textPlusBox = document . getElementById ( 'textPlusBox' ) ;
let textMinusBox = document . getElementById ( 'textMinusBox' ) ;
let wordCountBox = document . getElementById ( 'wordCountBox' ) ;
let removeBox = document . getElementById ( "removeBox" )
2024-05-20 20:24:43 +01:00
let importFile = document . getElementById ( "importFile" )
2024-07-05 22:46:53 +01:00
let importFileConfirm = document . getElementById ( "importFileConfirm" )
2024-03-12 18:34:05 +00:00
let selectedNote = 0
let timer
let waitTime = 400
2024-05-20 20:24:43 +01:00
let indiv = false
let mobile = false
2024-06-23 15:49:01 +01:00
let selectLatestNote = false
2024-03-12 18:34:05 +00:00
2024-07-06 16:02:20 +01:00
async function getKey ( ) {
let password = localStorage . getItem ( "DONOTSHARE-password" )
let cryptoKey = await window . crypto . subtle . importKey ( "raw" , new TextEncoder ( ) . encode ( password ) , "PBKDF2" , false , [ "deriveBits" , "deriveKey" ] )
let salt = new TextEncoder ( ) . encode ( "I love Burgernotes!" )
return await window . crypto . subtle . deriveKey ( {
name : "PBKDF2" ,
salt ,
iterations : 100000 ,
hash : "SHA-512"
} , cryptoKey , { name : "AES-GCM" , length : 256 } , true , [ "encrypt" , "decrypt" ] )
}
function encrypt ( text ) {
getKey ( )
. then ( ( key ) => {
let iv = window . crypto . getRandomValues ( new Uint8Array ( 12 ) )
window . crypto . subtle . encrypt ( {
name : "AES-GCM" ,
iv : iv
} , key , new TextEncoder ( ) . encode ( text ) )
. then ( ( encrypted ) => {
return btoa ( JSON . stringify ( {
encrypted : encrypted ,
iv : iv
} ) )
} )
} )
}
function decrypt ( encrypted ) {
getKey ( )
. then ( ( key ) => {
} )
}
2024-07-02 18:25:23 +01:00
function handleGesture ( ) {
if ( indiv ) {
indiv = false
notesBar . style . width = "100%" ;
noteBoxDiv . style . width = "0px"
if ( selectedNote !== 0 ) {
noteBoxDiv . readOnly = true
}
notesDiv . classList . remove ( "hidden" )
noteBoxDiv . classList . add ( "hidden" )
backButton . classList . add ( "hidden" )
newNote . classList . remove ( "hidden" )
} else {
indiv = true
noteBoxDiv . style . width = "100%" ;
notesBar . style . width = "0px"
if ( selectedNote !== 0 ) {
noteBoxDiv . readOnly = false
}
notesDiv . classList . add ( "hidden" )
noteBoxDiv . classList . remove ( "hidden" )
backButton . classList . remove ( "hidden" )
newNote . classList . add ( "hidden" )
}
}
2024-07-02 18:13:28 +01:00
// Init the note box
document . addEventListener ( "DOMContentLoaded" , function ( ) {
pell . init ( {
element : pellAttacher ,
onChange : html => console . log ( html ) ,
defaultParagraphSeparator : 'br' ,
styleWithCSS : false ,
classes : {
actionbar : 'pell-actionbar' ,
button : 'pell-button' ,
content : 'pell-content' ,
selected : 'pell-button-selected'
2024-07-02 19:04:13 +01:00
} ,
actions : [
"bold" ,
"italic" ,
"underline" ,
"strikethrough" ,
"heading1" ,
"heading2" ,
"paragraph" ,
"quote" ,
"olist" ,
"ulist" ,
"code" ,
"line" ,
"link" ,
{
name : 'uploadimage' ,
icon : '📁' ,
title : 'Upload image' ,
result : function result ( ) {
async function doStuff ( ) {
2024-07-05 22:46:53 +01:00
browseButton . classList . remove ( "hidden" )
2024-07-02 19:04:13 +01:00
displayError ( "Select an image to upload:" )
await waitForConfirm ( )
2024-07-05 22:46:53 +01:00
browseButton . classList . add ( "hidden" )
let file = uploadThing . files [ 0 ]
2024-07-02 19:04:13 +01:00
if ( file ) {
let reader = new FileReader ( )
reader . readAsDataURL ( file )
2024-07-05 22:46:53 +01:00
uploadThing . files = null
2024-07-02 19:04:13 +01:00
reader . onload = function ( ) {
pell . exec ( 'insertImage' , reader . result ) ;
}
}
}
doStuff ( ) ;
}
} ,
"image" ,
] ,
2024-07-02 18:13:28 +01:00
} )
let noteBox = document . getElementsByClassName ( "pell-content" ) [ 0 ]
if ( /Android|iPhone|iPod/i . test ( navigator . userAgent ) ) {
mobile = true
noteBoxDiv . classList . add ( "mobile" )
noteBoxDiv . style . width = "0px" ;
notesBar . style . width = "100%"
topBar . style . width = "100%"
noteBoxDiv . readOnly = true
2024-06-25 19:43:24 +01:00
noteBoxDiv . classList . add ( "hidden" )
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
let touchstartX , touchstartY , touchendX , touchendY
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
notesBar . addEventListener ( "touchstart" , function ( event ) {
touchstartX = event . changedTouches [ 0 ] . screenX ;
touchstartY = event . changedTouches [ 0 ] . screenY ;
} , false ) ;
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
notesBar . addEventListener ( "touchend" , function ( event ) {
touchendX = event . changedTouches [ 0 ] . screenX ;
touchendY = event . changedTouches [ 0 ] . screenY ;
if ( touchendX < touchstartX - 75 ) {
handleGesture ( ) ;
}
} , false ) ;
noteBox . addEventListener ( "touchstart" , function ( event ) {
touchstartX = event . changedTouches [ 0 ] . screenX ;
touchstartY = event . changedTouches [ 0 ] . screenY ;
} , false ) ;
noteBox . addEventListener ( "touchend" , function ( event ) {
touchendX = event . changedTouches [ 0 ] . screenX ;
touchendY = event . changedTouches [ 0 ] . screenY ;
if ( touchendX > touchstartX + 75 ) {
handleGesture ( ) ;
}
} , false ) ;
2024-04-25 22:34:18 +01:00
}
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
noteBox . innerText = ""
noteBox . readOnly = true
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
let noteCount = 0
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
function displayError ( message ) {
errorDiv . classList . remove ( "hidden" )
optionsCoverDiv . classList . remove ( "hidden" )
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
errorMessageThing . innerHTML = message
2024-03-12 18:34:05 +00:00
}
2024-07-02 18:13:28 +01:00
closeErrorButton . addEventListener ( "click" , ( ) => {
errorDiv . classList . add ( "hidden" )
optionsCoverDiv . classList . add ( "hidden" )
} ) ;
closeErrorButton . addEventListener ( "click" , ( ) => {
errorDiv . classList . add ( "hidden" )
optionsCoverDiv . classList . add ( "hidden" )
errorInput . classList . add ( "hidden" )
cancelErrorButton . classList . add ( "hidden" )
} ) ;
function updateFont ( ) {
currentFontSize = localStorage . getItem ( "SETTING-fontsize" )
noteBox . style . fontSize = currentFontSize + "px"
textSizeBox . innerText = currentFontSize + "px"
}
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
async function checknetwork ( ) {
let loggedInEndpoint
if ( localStorage . getItem ( "legacy" ) === "true" ) {
loggedInEndpoint = "userinfo"
} else {
loggedInEndpoint = "loggedin"
2024-03-12 18:34:05 +00:00
}
2024-07-02 18:13:28 +01:00
fetch ( remote + "/api/" + loggedInEndpoint , {
method : "POST" ,
body : JSON . stringify ( {
secretKey : localStorage . getItem ( "DONOTSHARE-secretkey" ) ,
} ) ,
headers : {
"Content-Type" : "application/json; charset=UTF-8"
}
} )
. catch ( ( ) => {
noteBox . contentEditable = false
noteBox . innerHTML = "<h1>You are currently offline.</h1>"
displayError ( "Failed to connect to the server.\nPlease check your internet connection." )
} )
. then ( ( response ) => response )
. then ( ( response ) => {
if ( response . status === 400 ) {
2024-05-24 19:48:24 +01:00
displayError ( "Something went wrong! Signing you out..." )
2024-03-12 18:34:05 +00:00
closeErrorButton . classList . add ( "hidden" )
2024-07-02 18:13:28 +01:00
//usernameBox.innerText = ""
2024-03-12 18:34:05 +00:00
setTimeout ( function ( ) {
2024-04-28 23:48:03 +01:00
window . location . replace ( "/logout" )
2024-03-12 18:34:05 +00:00
} , 2500 ) ;
2024-07-02 18:13:28 +01:00
} else if ( response . status === 200 ) {
updateUserInfo ( )
2024-03-12 18:34:05 +00:00
} else {
2024-07-02 18:13:28 +01:00
noteBox . readOnly = true
noteBox . innerHTML = "<h1>You are currently offline.</h1>"
displayError ( "Failed to connect to the server.\nPlease check your internet connection." )
2024-03-12 18:34:05 +00:00
}
2024-07-02 18:13:28 +01:00
} ) ;
}
if ( localStorage . getItem ( "SETTING-fontsize" ) === null ) {
localStorage . setItem ( "SETTING-fontsize" , "16" )
updateFont ( )
} else {
updateFont ( )
}
textPlusBox . addEventListener ( "click" , ( ) => {
localStorage . setItem ( "SETTING-fontsize" , String ( Number ( localStorage . getItem ( "SETTING-fontsize" ) ) + Number ( 1 ) ) )
updateFont ( )
} ) ;
textMinusBox . addEventListener ( "click" , ( ) => {
localStorage . setItem ( "SETTING-fontsize" , String ( Number ( localStorage . getItem ( "SETTING-fontsize" ) ) - Number ( 1 ) ) )
updateFont ( )
} ) ;
function truncateString ( str , num ) {
if ( str . length > num ) {
return str . slice ( 0 , num ) + ".." ;
} else {
return str ;
}
}
function updateUserInfo ( ) {
fetch ( remote + "/api/userinfo" , {
2024-03-12 18:34:05 +00:00
method : "POST" ,
body : JSON . stringify ( {
secretKey : secretkey
} ) ,
headers : {
"Content-Type" : "application/json; charset=UTF-8"
}
} )
. then ( ( response ) => {
2024-07-02 18:13:28 +01:00
async function doStuff ( ) {
if ( response . status === 500 ) {
displayError ( "Something went wrong! Signing you out..." )
closeErrorButton . classList . add ( "hidden" )
setTimeout ( function ( ) {
window . location . replace ( "/logout" )
} , 2500 ) ;
} else {
let responseData = await response . json ( )
usernameThing . innerText = "Username: " + responseData [ "username" ]
storageThing . innerText = "You've used " + formatBytes ( responseData [ "storageused" ] ) + " out of " + formatBytes ( responseData [ "storagemax" ] )
storageProgressThing . value = responseData [ "storageused" ]
storageProgressThing . max = responseData [ "storagemax" ]
noteCount = responseData [ "notecount" ]
}
2024-03-12 18:34:05 +00:00
}
2024-06-27 17:57:05 +01:00
2024-07-02 18:13:28 +01:00
doStuff ( )
} ) ;
2024-06-27 17:57:05 +01:00
}
2024-07-02 18:13:28 +01:00
usernameBox . addEventListener ( "click" , ( ) => {
optionsCoverDiv . classList . remove ( "hidden" )
optionsDiv . classList . remove ( "hidden" )
updateUserInfo ( )
} ) ;
logOutButton . addEventListener ( "click" , ( ) => {
window . location . replace ( "/logout" )
} ) ;
exitThing . addEventListener ( "click" , ( ) => {
optionsDiv . classList . add ( "hidden" )
optionsCoverDiv . classList . add ( "hidden" )
} ) ;
deleteMyAccountButton . addEventListener ( "click" , ( ) => {
if ( confirm ( "Are you REALLY sure that you want to delete your account? There's no going back!" ) === true ) {
fetch ( remote + "/api/deleteaccount" , {
2024-06-27 17:57:05 +01:00
method : "POST" ,
body : JSON . stringify ( {
2024-07-02 18:13:28 +01:00
secretKey : secretkey
2024-06-27 17:57:05 +01:00
} ) ,
headers : {
2024-07-02 18:13:28 +01:00
"Content-Type" : "application/json; charset=UTF-8"
2024-06-27 17:57:05 +01:00
}
} )
2024-07-02 18:13:28 +01:00
. then ( ( response ) => {
if ( response . status === 200 ) {
window . location . href = "/logout"
} else {
displayError ( "Failed to delete account (HTTP error code " + response . status + ")" )
}
} )
2024-06-27 17:57:05 +01:00
}
2024-07-02 18:13:28 +01:00
} ) ;
async function waitForConfirm ( ) {
let resolvePromise ;
const promise = new Promise ( resolve => resolvePromise = resolve ) ;
closeErrorButton . addEventListener ( "click" , ( ) => {
resolvePromise ( ) ;
} ) ;
await promise ;
}
async function hashpass ( pass ) {
let key = pass
for ( let i = 0 ; i < 128 ; i ++ ) {
key = await hashwasm . sha3 ( key )
}
return key
}
changePasswordButton . addEventListener ( "click" , ( ) => {
optionsDiv . classList . add ( "hidden" )
async function doStuff ( ) {
async function fatalError ( notes , passwordBackup ) {
displayError ( "Something went wrong! Your password change has failed. Attempting to revert changes..." )
password = passwordBackup
localStorage . setItem ( "DONOTSHARE-password" , password )
let changePasswordBackResponse = await fetch ( remote + "/api/changepassword" , {
2024-06-27 17:57:05 +01:00
method : "POST" ,
body : JSON . stringify ( {
secretKey : secretkey ,
2024-07-02 18:13:28 +01:00
newPassword : await hashpass ( oldPass )
2024-06-27 17:57:05 +01:00
} ) ,
headers : {
"Content-Type" : "application/json; charset=UTF-8" ,
"X-Burgernotes-Version" : "200"
}
} )
2024-07-02 18:13:28 +01:00
if ( changePasswordBackResponse . status === 200 ) {
let responseStatus = await importNotes ( notes )
if ( responseStatus === 500 ) {
closeErrorButton . classList . remove ( "hidden" )
displayError ( "Failed to revert changes. Please delete this user account and sign-up again, then re-import the notes. Click Ok to download the notes to import later." )
await waitForConfirm ( )
downloadObjectAsJson ( notes , "data" )
2024-06-27 17:57:05 +01:00
} else {
2024-07-02 18:13:28 +01:00
closeErrorButton . classList . remove ( "hidden" )
displayError ( "Password change failed! Changes have been reverted." )
updateNotes ( )
2024-06-27 17:57:05 +01:00
}
} else {
2024-07-02 18:13:28 +01:00
displayError ( "Failed to revert changes. Please delete this user account and sign-up again, then re-import the notes. Click Ok to download the notes to import later." )
downloadObjectAsJson ( notes , "data" )
2024-06-27 17:57:05 +01:00
}
}
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
displayError ( "Confirm your current password to change it" )
errorInput . type = "password"
errorInput . classList . remove ( "hidden" )
await waitForConfirm ( )
const oldPass = errorInput . value
errorInput . classList . add ( "hidden" )
if ( await hashwasm . sha512 ( oldPass ) !== password ) {
displayError ( "Incorrect password!" )
} else {
errorInput . value = ""
displayError ( "Enter your new password" )
errorInput . classList . remove ( "hidden" )
await waitForConfirm ( )
errorInput . classList . add ( "hidden" )
const newPass = errorInput . value
errorInput . type = "text"
errorInput . value = ""
if ( newPass . length < 8 ) {
displayError ( "Password must be at least 8 characters!" )
} else {
displayError ( "Changing your password. This process may take up to 5 minutes. Do NOT close the tab!" )
closeErrorButton . classList . add ( "hidden" )
const response = await fetch ( remote + "/api/changepassword" , {
method : "POST" ,
body : JSON . stringify ( {
secretKey : secretkey ,
newPassword : await hashpass ( newPass )
} ) ,
headers : {
"Content-Type" : "application/json; charset=UTF-8" ,
"X-Burgernotes-Version" : "200"
}
} )
if ( response . status === 200 ) {
let notes = await exportNotes ( )
let passwordBackup = password
password = await hashwasm . sha512 ( newPass )
localStorage . setItem ( "DONOTSHARE-password" , password )
let purgeNotes = await fetch ( remote + "/api/purgenotes" , {
2024-03-12 18:34:05 +00:00
method : "POST" ,
body : JSON . stringify ( {
2024-07-02 18:13:28 +01:00
secretKey : secretkey
2024-03-12 18:34:05 +00:00
} ) ,
headers : {
"Content-Type" : "application/json; charset=UTF-8"
}
} )
2024-07-02 18:13:28 +01:00
if ( purgeNotes . status !== 200 ) {
fatalError ( notes , passwordBackup )
} else {
let responseStatus = await importNotes ( notes )
errorDiv . classList . add ( "hidden" )
if ( responseStatus !== 200 ) {
fatalError ( notes , passwordBackup )
} else {
closeErrorButton . classList . remove ( "hidden" )
displayError ( "Password changed!" )
updateNotes ( )
}
}
} else {
closeErrorButton . classList . remove ( "hidden" )
const data = await response . json ( )
console . log ( data )
displayError ( data [ "error" ] )
}
2024-03-12 18:34:05 +00:00
}
}
}
2024-07-02 18:13:28 +01:00
doStuff ( )
} )
importNotesButton . addEventListener ( "click" , ( ) => {
optionsDiv . classList . add ( "hidden" )
importNotesDiv . classList . remove ( "hidden" )
} ) ;
sessionManagerButton . addEventListener ( "click" , ( ) => {
optionsDiv . classList . add ( "hidden" )
sessionManagerDiv . classList . remove ( "hidden" )
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
fetch ( remote + "/api/sessions/list" , {
method : "POST" ,
body : JSON . stringify ( {
secretKey : secretkey
} ) ,
headers : {
"Content-Type" : "application/json; charset=UTF-8"
}
} )
. then ( ( response ) => {
async function doStuff ( ) {
let responseData = await response . json ( )
document . querySelectorAll ( ".burgerSession" ) . forEach ( ( el ) => el . remove ( ) ) ;
let ua ;
for ( let i in responseData ) {
let sessionElement = document . createElement ( "div" )
let sessionText = document . createElement ( "p" )
let sessionImage = document . createElement ( "img" )
let sessionRemoveButton = document . createElement ( "button" )
sessionText . classList . add ( "w300" )
if ( responseData [ i ] [ "thisSession" ] === true ) {
sessionText . innerText = "(current) " + responseData [ i ] [ "device" ]
} else {
sessionText . innerText = responseData [ i ] [ "device" ]
2024-03-12 18:34:05 +00:00
}
2024-07-02 18:13:28 +01:00
sessionText . title = responseData [ i ] [ "device" ]
sessionRemoveButton . innerText = "x"
2024-06-23 15:49:01 +01:00
2024-07-02 18:13:28 +01:00
sessionImage . src = "/static/svg/device_other.svg"
2024-06-23 15:49:01 +01:00
2024-07-02 18:13:28 +01:00
ua = responseData [ i ] [ "device" ]
2024-06-23 15:49:01 +01:00
2024-07-02 18:13:28 +01:00
if ( ua . includes ( "NT" ) || ua . includes ( "Linux" ) ) {
sessionImage . src = "/static/svg/device_computer.svg"
}
if ( ua . includes ( "iPhone" || ua . includes ( "Android" ) || ua . includes ( "iPod" ) ) ) {
sessionImage . src = "/static/svg/device_smartphone.svg"
}
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
sessionRemoveButton . addEventListener ( "click" , ( ) => {
fetch ( remote + "/api/sessions/remove" , {
2024-03-12 18:34:05 +00:00
method : "POST" ,
body : JSON . stringify ( {
secretKey : secretkey ,
2024-07-02 18:13:28 +01:00
sessionId : responseData [ i ] [ "id" ]
2024-03-12 18:34:05 +00:00
} ) ,
headers : {
"Content-Type" : "application/json; charset=UTF-8"
}
} )
2024-07-02 18:13:28 +01:00
. then ( ( ) => {
if ( responseData [ i ] [ "thisSession" ] === true ) {
window . location . replace ( "/logout" )
2024-03-12 18:34:05 +00:00
}
2024-07-02 18:13:28 +01:00
} ) ;
sessionElement . remove ( )
} ) ;
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
sessionElement . append ( sessionImage )
sessionElement . append ( sessionText )
sessionElement . append ( sessionRemoveButton )
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
sessionElement . classList . add ( "burgerSession" )
2024-06-23 15:49:01 +01:00
2024-07-02 18:13:28 +01:00
sessionDiv . append ( sessionElement )
}
}
2024-06-23 15:49:01 +01:00
2024-07-02 18:13:28 +01:00
doStuff ( )
} ) ;
} ) ;
exitImportThing . addEventListener ( "click" , ( ) => {
optionsDiv . classList . remove ( "hidden" )
importNotesDiv . classList . add ( "hidden" )
} ) ;
exitSessionsThing . addEventListener ( "click" , ( ) => {
optionsDiv . classList . remove ( "hidden" )
sessionManagerDiv . classList . add ( "hidden" )
} ) ;
2024-06-23 15:49:01 +01:00
2024-07-02 18:13:28 +01:00
function updateWordCount ( ) {
let wordCount = noteBox . innerText . split ( " " ) . length
if ( wordCount === 1 ) {
wordCount = 0
}
wordCountBox . innerText = wordCount + " words"
}
2024-06-23 15:49:01 +01:00
2024-07-02 18:13:28 +01:00
function selectNote ( nameithink ) {
document . querySelectorAll ( ".noteButton" ) . forEach ( ( el ) => el . classList . remove ( "selected" ) ) ;
let thingArray = Array . from ( document . querySelectorAll ( ".noteButton" ) ) . find ( el => String ( nameithink ) === String ( el . id ) ) ;
thingArray . classList . add ( "selected" )
2024-06-27 17:57:05 +01:00
2024-07-02 18:13:28 +01:00
fetch ( remote + "/api/readnote" , {
method : "POST" ,
body : JSON . stringify ( {
secretKey : secretkey ,
noteId : nameithink ,
} ) ,
headers : {
"Content-Type" : "application/json; charset=UTF-8"
}
} )
. catch ( ( ) => {
noteBox . contentEditable = false
noteBox . innerHTML = ""
displayError ( "Something went wrong... Please try again later!" )
} )
. then ( ( response ) => {
selectedNote = nameithink
if ( mobile ) {
handleGesture ( )
2024-06-23 15:49:01 +01:00
}
2024-07-02 18:13:28 +01:00
noteBox . contentEditable = true
noteBox . click ( )
2024-06-23 15:49:01 +01:00
2024-07-02 18:13:28 +01:00
async function doStuff ( ) {
let responseData = await response . json ( )
2024-06-23 15:49:01 +01:00
2024-07-02 18:13:28 +01:00
let bytes = CryptoJS . AES . decrypt ( responseData [ "content" ] , password ) ;
2024-07-02 18:36:00 +01:00
let cleanedHTML = bytes . toString ( CryptoJS . enc . Utf8 ) . replace ( /<(?!\/?(h1|h2|br|img|blockquote|ol|li|b|i|u|strike|p|pre|ul|hr|a)\b)[^>]*>/gi , '' )
2024-07-02 18:13:28 +01:00
noteBox . innerHTML = cleanedHTML . replace ( "\n" , "<br>" )
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
updateWordCount ( )
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
noteBox . addEventListener ( "input" , ( ) => {
updateWordCount ( )
clearTimeout ( timer ) ;
timer = setTimeout ( ( ) => {
let preEncryptedTitle = noteBox . innerText
2024-06-23 15:49:01 +01:00
2024-07-02 18:13:28 +01:00
if ( noteBox . innerText . substring ( 0 , noteBox . innerText . indexOf ( "\n" ) ) !== "" ) {
preEncryptedTitle = noteBox . innerText . substring ( 0 , noteBox . innerText . indexOf ( "\n" ) ) ;
}
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
preEncryptedTitle = truncateString ( preEncryptedTitle , 15 )
document . getElementById ( nameithink ) . innerText = preEncryptedTitle
let encryptedText = CryptoJS . AES . encrypt ( noteBox . innerHTML , password ) . toString ( ) ;
let encryptedTitle = CryptoJS . AES . encrypt ( preEncryptedTitle , password ) . toString ( ) ;
console . log ( encryptedTitle )
console . log ( encryptedText )
if ( selectedNote === nameithink ) {
fetch ( remote + "/api/editnote" , {
method : "POST" ,
body : JSON . stringify ( {
secretKey : secretkey ,
noteId : nameithink ,
content : encryptedText ,
title : encryptedTitle
} ) ,
headers : {
"Content-Type" : "application/json; charset=UTF-8"
}
2024-03-12 18:34:05 +00:00
} )
2024-07-02 18:13:28 +01:00
. then ( ( response ) => {
if ( response . status === 418 ) {
displayError ( "You've ran out of storage... Changes will not be saved until you free up storage!" )
}
} )
. catch ( ( ) => {
displayError ( "Failed to save changes, please try again later..." )
} )
}
} , waitTime ) ;
2024-03-12 18:34:05 +00:00
} ) ;
}
2024-06-23 15:49:01 +01:00
2024-07-02 18:13:28 +01:00
doStuff ( )
} ) ;
}
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
function updateNotes ( ) {
console . log ( "Notes updated" )
fetch ( remote + "/api/listnotes" , {
method : "POST" ,
body : JSON . stringify ( {
secretKey : secretkey
} ) ,
headers : {
"Content-Type" : "application/json; charset=UTF-8"
2024-03-12 18:34:05 +00:00
}
2024-07-02 18:13:28 +01:00
} )
. then ( ( response ) => {
async function doStuff ( ) {
noteBox . contentEditable = false
selectedNote = 0
noteBox . innerHTML = ""
clearTimeout ( timer )
updateWordCount ( )
let responseData = await response . json ( )
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
let decryptedResponseData = [ ]
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
let highestID = 0
let noteData ;
for ( let i in responseData ) {
noteData = responseData [ i ]
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
let bytes = CryptoJS . AES . decrypt ( noteData [ "title" ] , password ) ;
noteData [ "title" ] = bytes . toString ( CryptoJS . enc . Utf8 )
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
if ( noteData [ "id" ] > highestID ) {
highestID = noteData [ "id" ]
}
2024-05-20 20:24:43 +01:00
2024-07-02 18:13:28 +01:00
decryptedResponseData . push ( noteData )
console . log ( noteData )
}
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
document . querySelectorAll ( ".noteButton" ) . forEach ( ( el ) => el . remove ( ) ) ;
for ( let i in decryptedResponseData ) {
let noteData = decryptedResponseData [ i ]
2024-03-12 18:34:05 +00:00
2024-07-02 18:13:28 +01:00
let noteButton = document . createElement ( "button" ) ;
noteButton . classList . add ( "noteButton" )
notesDiv . append ( noteButton )
2024-04-24 20:25:23 +01:00
2024-07-02 18:13:28 +01:00
console . log ( noteData [ "title" ] )
2024-05-20 20:24:43 +01:00
2024-07-02 18:13:28 +01:00
if ( noteData [ "title" ] === "" ) {
console . log ( noteData [ "title" ] )
console . log ( "case" )
noteData [ "title" ] = "New note"
}
2024-05-20 20:24:43 +01:00
2024-07-02 18:13:28 +01:00
noteButton . id = noteData [ "id" ]
noteButton . innerText = truncateString ( noteData [ "title" ] , 15 )
noteButton . addEventListener ( "click" , ( event ) => {
if ( event . ctrlKey ) {
fetch ( remote + "/api/removenote" , {
method : "POST" ,
body : JSON . stringify ( {
secretKey : secretkey ,
noteId : noteData [ "id" ]
} ) ,
headers : {
"Content-Type" : "application/json; charset=UTF-8"
}
} )
. then ( ( ) => {
updateNotes ( )
} )
. catch ( ( ) => {
displayError ( "Something went wrong! Please try again later..." )
} )
} else {
selectNote ( noteData [ "id" ] )
}
} ) ;
2024-06-27 17:57:05 +01:00
}
2024-07-02 18:13:28 +01:00
document . querySelectorAll ( ".loadingStuff" ) . forEach ( ( el ) => el . remove ( ) ) ;
2024-05-20 20:24:43 +01:00
2024-07-02 18:13:28 +01:00
if ( selectLatestNote === true ) {
selectNote ( highestID )
selectLatestNote = false
}
}
2024-05-20 20:24:43 +01:00
2024-07-02 18:13:28 +01:00
doStuff ( )
} ) ;
}
updateNotes ( )
newNote . addEventListener ( "click" , ( ) => {
let noteName = "New note"
2024-06-23 15:49:01 +01:00
selectLatestNote = true
2024-07-02 18:13:28 +01:00
console . log ( selectLatestNote )
// create fake item
document . querySelectorAll ( ".noteButton" ) . forEach ( ( el ) => el . classList . remove ( "selected" ) ) ;
let noteButton = document . createElement ( "button" ) ;
noteButton . classList . add ( "noteButton" )
notesDiv . append ( noteButton )
noteButton . innerText = "New note"
noteButton . style . order = "-1"
noteButton . classList . add ( "selected" )
noteBox . click ( )
let encryptedName = CryptoJS . AES . encrypt ( noteName , password ) . toString ( CryptoJS . enc . Utf8 ) ;
fetch ( remote + "/api/newnote" , {
2024-03-12 18:34:05 +00:00
method : "POST" ,
body : JSON . stringify ( {
secretKey : secretkey ,
2024-07-02 18:13:28 +01:00
noteName : encryptedName ,
2024-03-12 18:34:05 +00:00
} ) ,
headers : {
"Content-Type" : "application/json; charset=UTF-8"
}
} )
2024-04-28 23:48:03 +01:00
. catch ( ( ) => {
2024-07-02 18:13:28 +01:00
displayError ( "Failed to create new note, please try again later..." )
2024-03-12 18:34:05 +00:00
} )
2024-07-02 18:13:28 +01:00
. then ( ( response ) => {
if ( response . status !== 200 ) {
updateNotes ( )
displayError ( "Failed to create new note (HTTP error code " + response . status + ")" )
} else {
updateNotes ( )
}
} ) ;
} ) ;
function downloadObjectAsJson ( exportObj , exportName ) {
let dataStr = "data:text/json;charset=utf-8," + JSON . stringify ( exportObj ) ;
let downloadAnchorNode = document . createElement ( "a" ) ;
downloadAnchorNode . setAttribute ( "href" , dataStr ) ;
downloadAnchorNode . setAttribute ( "download" , exportName + ".json" ) ;
document . body . appendChild ( downloadAnchorNode ) ;
downloadAnchorNode . click ( ) ;
downloadAnchorNode . remove ( ) ;
2024-03-12 18:34:05 +00:00
}
2024-07-02 18:13:28 +01:00
async function exportNotes ( ) {
let exportNotesFetch = await fetch ( remote + "/api/exportnotes" , {
method : "POST" ,
body : JSON . stringify ( {
secretKey : secretkey
} ) ,
headers : {
"Content-Type" : "application/json; charset=UTF-8"
}
} )
let responseData = await exportNotesFetch . json ( )
for ( let i in responseData ) {
exportNotes . innerText = "Decrypting " + i + "/" + noteCount
2024-04-24 20:25:23 +01:00
2024-07-02 18:13:28 +01:00
let bytes = CryptoJS . AES . decrypt ( responseData [ i ] [ "title" ] , password ) ;
responseData [ i ] [ "title" ] = bytes . toString ( CryptoJS . enc . Utf8 )
2024-03-29 20:05:46 +00:00
2024-07-02 18:13:28 +01:00
let bytesd = CryptoJS . AES . decrypt ( responseData [ i ] [ "content" ] , password ) ;
responseData [ i ] [ "content" ] = bytesd . toString ( CryptoJS . enc . Utf8 )
}
return responseData
}
async function importNotes ( plaintextNotes ) {
for ( let i in plaintextNotes ) {
let originalTitle = plaintextNotes [ i ] [ "title" ] ;
plaintextNotes [ i ] [ "title" ] = CryptoJS . AES . encrypt ( originalTitle , password ) . toString ( ) ;
let originalContent = plaintextNotes [ i ] [ "content" ] ;
plaintextNotes [ i ] [ "content" ] = CryptoJS . AES . encrypt ( originalContent , password ) . toString ( ) ;
}
let importNotesFetch = await fetch ( remote + "/api/importnotes" , {
method : "POST" ,
body : JSON . stringify ( {
"secretKey" : localStorage . getItem ( "DONOTSHARE-secretkey" ) ,
"notes" : JSON . stringify ( plaintextNotes )
} ) ,
headers : {
"Content-Type" : "application/json; charset=UTF-8"
}
} )
return importNotesFetch . status
}
function firstNewVersion ( ) {
if ( localStorage . getItem ( "NEWVERSION" ) === "1.2" ) {
return false ;
} else {
localStorage . setItem ( "NEWVERSION" , "1.2" )
return true ;
}
}
2024-06-22 14:57:09 +01:00
2024-07-02 18:13:28 +01:00
exportNotesButton . addEventListener ( "click" , ( ) => {
let responseData = exportNotes ( )
downloadObjectAsJson ( responseData , "data" )
optionsDiv . classList . add ( "hidden" )
displayError ( "Exported notes!" )
} ) ;
2024-07-05 22:46:53 +01:00
importFileConfirm . addEventListener ( 'click' , function ( ) {
2024-07-02 18:13:28 +01:00
let fileread = new FileReader ( )
fileread . addEventListener (
"load" ,
( ) => {
let decrypted = JSON . parse ( fileread . result . toString ( ) )
importNotes ( decrypted )
. then ( ( responseStatus ) => {
if ( responseStatus === 500 ) {
optionsDiv . classList . add ( "hidden" )
importNotesDiv . classList . add ( "hidden" )
displayError ( "Something went wrong! Perhaps your note file was invalid?" )
} else {
optionsDiv . classList . add ( "hidden" )
importNotesDiv . classList . add ( "hidden" )
displayError ( "Notes uploaded!" )
updateNotes ( )
}
} )
} ,
false ,
) ;
2024-07-05 22:46:53 +01:00
fileread . readAsText ( uploadThing . files [ 0 ] )
2024-07-02 18:13:28 +01:00
} )
removeBox . addEventListener ( "click" , ( ) => {
if ( selectedNote === 0 ) {
displayError ( "You need to select a note first!" )
} else {
selectLatestNote = true
fetch ( remote + "/api/removenote" , {
method : "POST" ,
body : JSON . stringify ( {
secretKey : secretkey ,
noteId : selectedNote
} ) ,
headers : {
"Content-Type" : "application/json; charset=UTF-8"
}
} )
. then ( ( ) => {
updateNotes ( )
} )
. catch ( ( ) => {
displayError ( "Something went wrong! Please try again later..." )
} )
}
} ) ;
if ( firstNewVersion ( ) ) {
displayError ( "What's new in Burgernotes 2.0?\nRestyled client\nAdded changing passwords\nAdded importing notes" )
}
checknetwork ( )
} )
2024-06-25 19:43:24 +01:00
// @license-end