* Added theme colors to form fields

* Added some basic table styles for inserting some shitty tables
* Made popup notification styles look better and work better on mobile
* Quick note now opens a note and not some weird page
* Menu collapses when page is small, behaves like mobile menu
* Added terms and conditions to help and login forms
* Added password change functionality
* Better styles for shared page
* Added some tests for changing password
This commit is contained in:
Max G committed 2020-07-14 05:31:02 +00:00
1 parent 47fff0e1ee
commit e7d1cc7bc9
16 files changed
+423 -142

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

+39 -1
View File
@@ -86,6 +86,8 @@ body {
text-align: center;
}
.ui.form input:not([type]),
.ui.form input:not([type]):focus,
.ui.form textarea:not([type]),
@@ -94,6 +96,21 @@ body {
background-color: var(--small_element_bg_color);
border-color: var(--dark_border_color);
}
.ui.form input[type="password"],
.ui.form input[type="text"],
.ui.input > input {
color: var(--text_color);
background-color: var(--small_element_bg_color);
border-color: var(--dark_border_color);
}
.ui.form input[type="password"]:focus, .ui.form input[type="password"]:active,
.ui.form input[type="text"]:focus, .ui.form input[type="text"]:active,
.ui.input > input:focus, .ui.input > input:active {
color: var(--text_color);
background-color: var(--small_element_bg_color);
border-color: var(--main-accent);
border-right-color: var(--main-accent) !important;
}
.ui.basic.label, .ui.header, .ui.header div.sub.header {
color: var(--text_color);
background-color: transparent;
@@ -358,10 +375,15 @@ i.green.icon.icon.icon.icon {
border-collapse: collapse;
}
tr {
display: flex;
}
th, td {
border: 1px solid #ddd;
border-bottom: 1px solid #ddd;
font-weight: normal;
flex: 1;
}
/* table:hover th, table:hover td {
border: 1px solid black;
@@ -371,6 +393,22 @@ i.green.icon.icon.icon.icon {
padding: 3px;
text-align: left;
}
.table-tic-table {
}
.table-tic-table > div {
height: 21px;
margin: 0;
padding: 0;
}
.tabletic {
display: inline-block;
border: 1px solid black;
border-radius: 2px;
width: 20px;
height: 20px;
margin: 0 1px 1px 0;
cursor: pointer;
}
.t-table {
width: 100%;
@@ -430,7 +468,7 @@ i.green.icon.icon.icon.icon {
font-family: 'Icons';
content: "\f058";
color: #21BA45;
color: var(--main-accent);
opacity: 1;
}
}
@@ -2,30 +2,31 @@
.popup-body {
position: fixed;
bottom: 15px;
top: 15px;
left: 15px;
min-height: 50px;
min-width: 200px;
max-width: calc(100% - 20px);
max-width: calc(100% - 30px);
z-index: 1002;
border-top: 2px solid #21ba45;
box-shadow: 0px 0px 5px 2px rgba(140,140,140,1);
border-top-right-radius: 4px;
border-top-left-radius: 4px;
border-radius: 4px;
color: white;
background-color: var(--main-accent);
}
.popup-row {
padding: 1em 5px;
cursor: pointer;
white-space: nowrap;
}
.popup-row > span {
width: calc(100% - 50px);
/*width: calc(100% - 50px);*/
display: inline-block;
text-align: center;
text-align: left;
box-sizing: border-box;
padding: 0 10px 0;
font-size: 1.25em;
border-radius: 4px;
}
.popup-row + .popup-row {
border-top: 1px solid #FFF;
@@ -36,12 +37,10 @@
}
@keyframes slide-in-bottom {
0% {
transform: translateY(1000px);
opacity: 0;
transform: translateY(-1000px);
}
100% {
transform: translateY(0);
opacity: 1;
}
}
@@ -63,14 +62,46 @@
}
}
.meter {
height: 2px;
display: inline-block;
width: 100%;
position: fixed;
top: 0;
left: 0;
right: 0;
overflow: hidden;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
}
.meter span {
display: block;
height: 100%;
}
.progress {
background-color: white;
animation: progressBar 3s linear;
animation-fill-mode: both;
}
@keyframes progressBar {
0% { width: 0; }
100% { width: 100%; }
}
</style>
<template>
<div class="popup-body slide-in-bottom" v-on:click="dismiss" v-if="notifications.length > 0">
<div class="popup-row color-fade" v-for="item in notifications">
<span>{{ item }}</span>
<div class="popup-row" v-for="item in notifications">
<div class="meter">
<span><span class="progress"></span></span>
</div>
<span><i class="small info circle icon"></i>{{ item }}</span>
</div>
</div>
</template>
@@ -94,9 +125,9 @@
},
mounted(){
// this.$bus.$emit('notification', 'Password Protection Removed')
// this.$bus.$emit('notification', 'Password Protection Removed')
// this.$bus.$emit('notification', 'Password Protection Removed')
// this.$bus.$emit('notification', 'Password Protection Removed Login did not succeed')
// this.$bus.$emit('notification', 'Password Protection Removed your life is exposed to the internet')
// this.$bus.$emit('notification', 'Password Protection Removed everyone can see everything')
},
methods: {
@@ -105,7 +136,7 @@
clearTimeout(this.totalTimeout)
this.totalTimeout = setTimeout(() => {
this.dismiss()
}, 4000)
}, 3000)
},
dismiss(){
this.notifications = []
+51 -7
View File
@@ -133,9 +133,23 @@
<div class="mobile-button"></div>
<router-link v-if="loggedIn" to="/quick" class="mobile-button" exact-active-class="active">
<!-- open straight to note -->
<router-link
v-if="loggedIn && $store.getters.totals && $store.getters.totals['quickNote']"
exact-active-class="active"
class="mobile-button"
:to="`/notes/open/${$store.getters.totals['quickNote']}`">
<i class="green sticky note outline icon"></i>
</router-link>
<!-- create new and redirect to new note id -->
<a
v-if="loggedIn && $store.getters.totals && !$store.getters.totals['quickNote']"
v-on:click="newQuickNote()"
exact-active-class="active"
class="mobile-button">
<i class="green sticky note outline icon"></i>
</a>
<router-link v-if="loggedIn" class="mobile-button" exact-active-class="active" to="/notes" v-on:click.native="emitReloadEvent()">
<logo class="logo-display" color="var(--main-accent)" />
@@ -167,10 +181,8 @@
<div class="global-menu" v-if="!collapsed" v-on:click="menuClicked">
<div class="menu-section" v-on:click="collapseMenu">
<!-- <div class="menu-item menu-button" > -->
<i class="white angle left icon"></i>
<logo class="menu-logo-display" color="var(--main-accent)" />
<!-- </div> -->
<i class="white angle left icon"></i>
<logo class="menu-logo-display" color="var(--main-accent)" />
</div>
<div class="menu-section" v-if="loggedIn">
@@ -216,9 +228,26 @@
</div>
<div class="menu-section" v-if="loggedIn">
<router-link v-if="loggedIn" exact-active-class="active" class="menu-item menu-button" to="/quick">
<!-- open straight to note -->
<router-link
v-if="loggedIn && $store.getters.totals && $store.getters.totals['quickNote']"
exact-active-class="active"
class="menu-item menu-button"
:to="`/notes/open/${$store.getters.totals['quickNote']}`">
<i class="sticky note outline icon"></i>Scratch Pad
</router-link>
<!-- create new and redirect to new note id -->
<a
v-if="loggedIn && $store.getters.totals && !$store.getters.totals['quickNote']"
v-on:click="newQuickNote()"
exact-active-class="active"
class="menu-item menu-button">
<i class="sticky note outline icon"></i>Scratch Pad
</a>
</div>
<div class="menu-section" v-if="!loggedIn">
@@ -244,7 +273,7 @@
<div class="menu-section">
<router-link class="menu-item menu-button" exact-active-class="active" to="/help">
<i class="question circle outline icon"></i>Help / Terms
<i class="question circle outline icon"></i>Help | Terms
</router-link>
</div>
@@ -304,6 +333,8 @@
this.$store.dispatch('fetchAndUpdateUserTotals')
this.version = localStorage.getItem('currentVersion')
}
this.resizeEventHandler() //Trigger resize event
},
computed: {
@@ -329,16 +360,29 @@
},
},
methods: {
newQuickNote(){
axios.post('/api/quick-note/get')
.then( ({data}) => {
console.log(data)
this.$router.push({'path':'/notes/open/'+data.noteId})
})
},
resizeEventHandler(e) {
clearTimeout(this.resizeDebounce)
this.resizeDebounce = setTimeout(() => {
this.mobile = false
this.menuOpen = false
this.collapsed = false
if(window.innerWidth < 700){
this.collapsed = true
this.mobile = true
}
}, 100)
},
+8 -5
View File
@@ -69,10 +69,6 @@
<i class="grip lines icon"></i>
</div>
<div class="edit-button" v-on:click="insertTable(4,4)" data-tooltip="Insert Table" data-position="bottom center" data-inverted>
<i class="book dead icon"></i>
</div>
<div class="edit-button" v-on:click="removeFormatting()" data-tooltip="Remove Formatting" data-position="bottom center" data-inverted>
<i class="remove format icon"></i>
</div>
@@ -276,7 +272,14 @@
<!-- create table option -->
<side-slide-menu v-if="table" v-on:close="table = false; fetchNoteTags()" name="table" :style-object="styleObject">
<div class="ui basic segment">
Create a table
<h2>Insert Table</h2>
<div class="table-tic-table">
<div v-for="i in 10">
<div v-for="j in 10" class="tabletic" v-on:click="insertTable(i,j)">
</div>
</div>
</div>
</div>
</side-slide-menu>
@@ -12,6 +12,7 @@
<ul>
<li>Shared notes can be read and edited by you and all shared users.</li>
<li>Shared notes can only be shared by the creator of the note.</li>
<li>If you turn off sharing, no one else can read the note.</li>
</ul>
</div>
+11 -47
View File
@@ -345,62 +345,26 @@ const SquireButtonFunctions = {
this.editor.focus()
this.editor.moveCursorToEnd()
},
insertTable(wide, tall){
console.log('Insert a table')
insertTable(tall, wide){
console.log(`Table: ${wide} x ${tall}`)
let tableSyntax = `
<div>
<table>
<tr>
<th><p><br></p></th>
<th><p><br></p></th>
</tr>
<tr>
<td><p><br></p></td>
<td><p><br></p></td>
</tr>
<tr>
<td><p><br></p></td>
<td><p><br></p></td>
</tr>
</table>
</div>
`
tableSyntax = `
<span class="t-table">
<span>
<span>
<p><br></p>
</span>
<span>
<p><br></p>
</span>
</span>
<span>
<span>
<p><br></p>
</span>
<span>
<p><br></p>
</span>
</span>
</span>
<p><br></p>
`
tableSyntax = ''
tableSyntax += '<span class="t-table">'
//Insert a table
let tableSyntax = '<div>'
tableSyntax += '<table>'
for (let i = 0; i < tall; i++) {
tableSyntax += '<tr>'
for (let j = 0; j < wide; j++) {
tableSyntax += '<td><p><br></p></td>'
}
tableSyntax += '</tr>'
}
tableSyntax += '</span><p><br></p>'
tableSyntax += '</table></div><p><br></p>'
this.editor.insertHTML(tableSyntax)
this.editor.focus()
this.editor.moveCursorToEnd()
this.$router.go(-1)
},
},
}
+21 -23
View File
@@ -1,31 +1,29 @@
<template>
<div class="ui container">
<div class="ui grid">
<div class="sixteen wide column"></div>
<div class="sixteen wide column squire-box">
<div class="ui grid">
<div class="sixteen wide column"></div>
<div class="sixteen wide column">
<h2 class="ui dividing header">
Help
</h2>
<div class="ui segment">
<!-- Content copied from note -->
<!-- https://www.solidscribe.com/#/notes/open/552 -->
<p><b>Only Note Text is Encrypted</b><br></p><blockquote><p>Only you can read your notes. Encryption is the transformation of data into a form unreadable by anyone without the password. Its purpose is to ensure privacy by keeping the information hidden from anyone for whom it is not intended, even those who can see the encrypted data. Even if every note in the database was leaked, nothing would be readable. If the government asked for your notes, it would all be gibberish. <br></p></blockquote><p><br></p><p><b>Some Data is not encrypted</b><br></p><blockquote><p>Everything isn't encrypted, to keep up ease of use. Files, Tags and Attachments are not encrypted.<br></p></blockquote><p><br></p><p><b>Searching is somewhat limited</b><br></p><blockquote><p>Since every note is encrypted, searching is limited. To maintain security, only single words can be searched. Your search index is private and Encrypted.<br></p></blockquote><p><br></p><p><b>The Scrat</b><b></b><b>ch Pad</b><b></b><br></p><blockquote><p>The Scratch Pad was designed to allow rapid input to a single note. Rather than junking up all your notes with random links, numbers or haikus, you can put them all in one place. <br></p><ul><li>All data pushed to the quick note can still be edited like a normal note.<br></li><li>Creating a new quick note will not erase your old <br></li></ul></blockquote><p><br></p><p><b>Flux Theme</b><br></p><blockquote><p>Flux theme limits the amount of blue emitted by your screen. Most things turn sepia and a filter is applied to images to make them more sepia. Less blue light at night is supposed to be helpful for falling asleep.<br></p><p>Here is some good research on the topic: <a href="https://justgetflux.com/research.html">https://justgetflux.com/research.html</a><br></p></blockquote><p><br></p><p><b>Text Editor Keyboard Shor</b><b>tcuts</b><br></p><blockquote><p>Number List - CTRL + SHIFT + 9<br></p><p>Todo List - CTRL + SHIFT + 8<br></p><p>Underline CTRL + u<br></p><p>Bold - CTRL + b<br></p><p>Quote - CRTL + i<br></p><p>Indent - CTL + ]<br></p><p>Outdent - CRTL + [<br></p><p>Undo - CTRL + z<br></p><p>Redo - CTRL + y<br></p></blockquote><p><br></p><p><b>Shared Notes and Security</b><br></p><blockquote><p>Shared notes still respect privacy but use a different security scheme. Instead of encrypting the note with your password, a shared password is created. This note then uses <a href="https://en.wikipedia.org/wiki/Public-key_cryptography">public-key cryptography</a> to share the note with other users, while still making it unreadable to anyone else. <br></p><ul><li>You can revoke any users access to a shared note at any time.<br></li><li>Notes you share can not be shared by other people.<br></li><li>If you turn off sharing, all users lose access and the note is reverted to the default security scheme.<br></li></ul></blockquote><p><b>Public Links for shared notes</b><br></p><blockquote><p>It is possible to generate a public URL for shared notes. This is a huge security risk and exposes the Encryption Key for the note. The encryption key to a shared note can easily be changed by turning off sharing, then turning it back on. <br></p><p><br></p></blockquote><p><b>Links in notes</b><br></p><blockquote><p>Links put into notes are automatically scraped. This means the data from the link will be scanned to get an image and some text from the website to help make that link more accessible in the future. You can edit the text of scarped links and any time and search for it later. <br></p></blockquote><p><br></p><p><b>Files in notes</b><br></p><blockquote><p>Files can be uploaded to notes. If its an image, the picture will be put into the note.<br></p><p>Images added to notes will have text scanned, so it can be searched (This isn't super accurate so don't rely to heavily on it.) The text can be updated at any time.<br></p></blockquote><p><br></p><p><b>Deleting notes</b><br></p><blockquote><p>When<b> </b>notes are deleted, none of the files related to the note are deleted. <br></p></blockquote><p><br></p><p><b>Daily Backups</b><br></p><blockquote><p>All notes are backed up, every night, at midnight. If there is data loss, it can be restored from a backup. If you experience some sort of cataclysmic data loss please contact the system administrator for a copy of your data or a restoration procedure.<br></p></blockquote>
</div>
<h2 class="ui dividing header">
Solid Scribe Terms of Use
</h2>
<div class="ui segment">
<p>Welcome to Solid Scribe’s web-based application at solidscribe.com.<br></p><p><br></p><p>Your use of the Site and/or participation in any of the Services offered through the Site, is subject to these Terms of Use.<br></p><p>By registering an an account or using the Site you agree to be bound by these Terms of Use.<br></p><p><br></p><p>The Company reserves the right to change these Terms of Use from time to time by publishing them on the Site.<br></p><p>By using the Site, you agree to the most current version of these Terms of Use as posted on the Site.<br></p><p><br></p><p>All content on the Site is provided "as is." Solid Scribe is not liable for any informational errors, incompleteness, delays or any actions taken in reliance on information contained on the Site. The Company cannot and does not guarantee that any content on the Site will be entirely accurate or up-to-date at all times as the information on the Site originates from various sources, which may or may not be within the control of the Company.<br></p><p><br></p><p>The Company is not responsible for any omission, deletion, failure to store, improper delivery or untimely delivery of any information or material. The Company is not responsible for any reliance upon or damage arising from the use of the Site, including technical damage resulting from downloading or accessing any information or material provided.<br></p><p><br></p><p>You understand and agree that the Company is not responsible for any content posted by you or third parties. You further understand that the Company does not monitor the content posted by other users.<br></p><p><br></p><p>The Company reserves the right to remove content that the Company deems inappropriate for any reason what so ever without notice. The Company also reserves the right, in the Company’s sole discretion, to remove a user's privilege to post content on the Site.<br></p><p><br></p><p>The Company does not in any manner endorse the content of its users and cannot and does not vouch for its reliability or otherwise accept liability for it.<br></p><p><br></p><p>Minors (persons under 18 years of age), persons or organizations that cannot enter into binding contracts under applicable law, and those who may be prevented by contractual obligations from entering into binding contracts with Solid Scribe are not allowed to use this Site.<br></p><p><br></p><p>The Company has the right, but not the obligation, to take any of the following actions in the Company’s sole discretion at any time and for any reason without providing you any prior notice:<br></p><p><br></p><p>1. Restrict, suspend, modify or terminate access to the Site or all or any part of the Company’s Services;<br></p><p><br></p><p>2. Change, suspend or discontinue all or any part of the Company’s Services;<br></p><p><br></p><p>3. Refuse, move, modify or remove any material submitted to the Site by any person, for any reason;<br></p><p><br></p><p>4. Refuse, move, modify or remove any content available on the Site;<br></p><p><br></p><p>5. Deactivate or delete your account and all related information and files in your account;<br></p><p><br></p><p>6. Establish, discontinue or change general practices and limits concerning use of the Site and the Company’s Services.<br></p><p><br></p><p>You agree that the Company is not liable to you or any third party for taking any of these actions. Any registration or other eligibility requirements are in the sole discretion of the Company and may be modified for any reason at any time.<br></p><p><br></p><p>YOUR INFORMATION AND CONTENT<br></p><p><br></p><p>Any information you provide to Solid Scribe or other users during your registration or use of the Site (in any public message area, through any mail feature, or otherwise generated out of your use of the Site or the Services), is subject to the following:<br></p><p><br></p><p>(a) You are solely responsible for the content of your information, postings or Notes. The Company reserves the right to take any action with respect to such information that it deems necessary or appropriate in its sole discretion for any reason, including if the Company believes information is inappropriate for the Site or the Services, may create liability for the Company.<br></p><p><br></p><p>(b) You agree that your information will not, to the best of your knowledge: (i) violate any law (including without limitation those governing export control, consumer protection, unfair competition, anti-discrimination or false advertising); or (ii) be libelous, defamatory, obscene, abusive, violate a third party's right to privacy, otherwise violate any applicable local, state, national or international law, amount to spamming or be otherwise inappropriate. You may not post content that degrades others on the basis of gender, race, class, ethnicity, national origin, religion, sexual preference, disability or other classification. Epithets and other language intended to intimidate, unlaLine truncated
</div>
<h2 class="ui dividing header">
Help
</h2>
<div class="ui segment squire-box">
<!-- Content copied from note -->
<!-- https://www.solidscribe.com/#/notes/open/552 -->
<p><b>Only Note Text is Encrypted</b><br></p><blockquote><p>Only you can read your notes. Encryption is the transformation of data into a form unreadable by anyone without the password. Its purpose is to ensure privacy by keeping the information hidden from anyone for whom it is not intended, even those who can see the encrypted data. Even if every note in the database was leaked, nothing would be readable. If the government asked for your notes, it would all be gibberish. <br></p></blockquote><p><br></p><p><b>Some Data is not encrypted</b><br></p><blockquote><p>Everything isn't encrypted, to keep up ease of use. Files, Tags and Attachments are not encrypted.<br></p></blockquote><p><br></p><p><b>Searching is somewhat limited</b><br></p><blockquote><p>Since every note is encrypted, searching is limited. To maintain security, only single words can be searched. Your search index is private and Encrypted.<br></p></blockquote><p><br></p><p><b>The Scrat</b><b></b><b>ch Pad</b><b></b><br></p><blockquote><p>The Scratch Pad was designed to allow rapid input to a single note. Rather than junking up all your notes with random links, numbers or haikus, you can put them all in one place. <br></p><ul><li>All data pushed to the quick note can still be edited like a normal note.<br></li><li>Creating a new quick note will not erase your old <br></li></ul></blockquote><p><br></p><p><b>Flux Theme</b><br></p><blockquote><p>Flux theme limits the amount of blue emitted by your screen. Most things turn sepia and a filter is applied to images to make them more sepia. Less blue light at night is supposed to be helpful for falling asleep.<br></p><p>Here is some good research on the topic: <a href="https://justgetflux.com/research.html">https://justgetflux.com/research.html</a><br></p></blockquote><p><br></p><p><b>Text Editor Keyboard Shor</b><b>tcuts</b><br></p><blockquote><p>Number List - CTRL + SHIFT + 9<br></p><p>Todo List - CTRL + SHIFT + 8<br></p><p>Underline CTRL + u<br></p><p>Bold - CTRL + b<br></p><p>Quote - CRTL + i<br></p><p>Indent - CTL + ]<br></p><p>Outdent - CRTL + [<br></p><p>Undo - CTRL + z<br></p><p>Redo - CTRL + y<br></p></blockquote><p><br></p><p><b>Shared Notes and Security</b><br></p><blockquote><p>Shared notes still respect privacy but use a different security scheme. Instead of encrypting the note with your password, a shared password is created. This note then uses <a href="https://en.wikipedia.org/wiki/Public-key_cryptography">public-key cryptography</a> to share the note with other users, while still making it unreadable to anyone else. <br></p><ul><li>You can revoke any users access to a shared note at any time.<br></li><li>Notes you share can not be shared by other people.<br></li><li>If you turn off sharing, all users lose access and the note is reverted to the default security scheme.<br></li></ul></blockquote><p><b>Public Links for shared notes</b><br></p><blockquote><p>It is possible to generate a public URL for shared notes. This is a huge security risk and exposes the Encryption Key for the note. The encryption key to a shared note can easily be changed by turning off sharing, then turning it back on. <br></p><p><br></p></blockquote><p><b>Links in notes</b><br></p><blockquote><p>Links put into notes are automatically scraped. This means the data from the link will be scanned to get an image and some text from the website to help make that link more accessible in the future. You can edit the text of scarped links and any time and search for it later. <br></p></blockquote><p><br></p><p><b>Files in notes</b><br></p><blockquote><p>Files can be uploaded to notes. If its an image, the picture will be put into the note.<br></p><p>Images added to notes will have text scanned, so it can be searched (This isn't super accurate so don't rely to heavily on it.) The text can be updated at any time.<br></p></blockquote><p><br></p><p><b>Deleting notes</b><br></p><blockquote><p>When<b> </b>notes are deleted, none of the files related to the note are deleted. <br></p></blockquote><p><br></p><p><b>Daily Backups</b><br></p><blockquote><p>All notes are backed up, every night, at midnight. If there is data loss, it can be restored from a backup. If you experience some sort of cataclysmic data loss please contact the system administrator for a copy of your data or a restoration procedure.<br></p></blockquote>
</div>
<h2 class="ui dividing header">
Solid Scribe Terms of Use
</h2>
<div class="ui segment">
<p>Welcome to Solid Scribe’s web-based application at solidscribe.com.<br></p><p><br></p><p>Your use of the Site and/or participation in any of the Services offered through the Site, is subject to these Terms of Use.<br></p><p>By registering an an account or using the Site you agree to be bound by these Terms of Use.<br></p><p><br></p><p>The Company reserves the right to change these Terms of Use from time to time by publishing them on the Site.<br></p><p>By using the Site, you agree to the most current version of these Terms of Use as posted on the Site.<br></p><p><br></p><p>All content on the Site is provided "as is." Solid Scribe is not liable for any informational errors, incompleteness, delays or any actions taken in reliance on information contained on the Site. The Company cannot and does not guarantee that any content on the Site will be entirely accurate or up-to-date at all times as the information on the Site originates from various sources, which may or may not be within the control of the Company.<br></p><p><br></p><p>The Company is not responsible for any omission, deletion, failure to store, improper delivery or untimely delivery of any information or material. The Company is not responsible for any reliance upon or damage arising from the use of the Site, including technical damage resulting from downloading or accessing any information or material provided.<br></p><p><br></p><p>You understand and agree that the Company is not responsible for any content posted by you or third parties. You further understand that the Company does not monitor the content posted by other users.<br></p><p><br></p><p>The Company reserves the right to remove content that the Company deems inappropriate for any reason what so ever without notice. The Company also reserves the right, in the Company’s sole discretion, to remove a user's privilege to post content on the Site.<br></p><p><br></p><p>The Company does not in any manner endorse the content of its users and cannot and does not vouch for its reliability or otherwise accept liability for it.<br></p><p><br></p><p>Minors (persons under 18 years of age), persons or organizations that cannot enter into binding contracts under applicable law, and those who may be prevented by contractual obligations from entering into binding contracts with Solid Scribe are not allowed to use this Site.<br></p><p><br></p><p>The Company has the right, but not the obligation, to take any of the following actions in the Company’s sole discretion at any time and for any reason without providing you any prior notice:<br></p><p><br></p><p>1. Restrict, suspend, modify or terminate access to the Site or all or any part of the Company’s Services;<br></p><p><br></p><p>2. Change, suspend or discontinue all or any part of the Company’s Services;<br></p><p><br></p><p>3. Refuse, move, modify or remove any material submitted to the Site by any person, for any reason;<br></p><p><br></p><p>4. Refuse, move, modify or remove any content available on the Site;<br></p><p><br></p><p>5. Deactivate or delete your account and all related information and files in your account;<br></p><p><br></p><p>6. Establish, discontinue or change general practices and limits concerning use of the Site and the Company’s Services.<br></p><p><br></p><p>You agree that the Company is not liable to you or any third party for taking any of these actions. Any registration or other eligibility requirements are in the sole discretion of the Company and may be modified for any reason at any time.<br></p><p><br></p><p>YOUR INFORMATION AND CONTENT<br></p><p><br></p><p>Any information you provide to Solid Scribe or other users during your registration or use of the Site (in any public message area, through any mail feature, or otherwise generated out of your use of the Site or the Services), is subject to the following:<br></p><p><br></p><p>(a) You are solely responsible for the content of your information, postings or Notes. The Company reserves the right to take any action with respect to such information that it deems necessary or appropriate in its sole discretion for any reason, including if the Company believes information is inappropriate for the Site or the Services, may create liability for the Company.<br></p><p><br></p><p>(b) You agree that your information will not, to the best of your knowledge: (i) violate any law (including without limitation those governing export control, consumer protection, unfair competition, anti-discrimination or false advertising); or (ii) be libelous, defamatory, obscene, abusive, violate a third party's right to privacy, otherwise violate any applicable local, state, national or international law, amount to spamming or be otherwise inappropriate. You may not post content that degrades others on the basis of gender, race, class, ethnicity, national origin, religion, sexual preference, disability or other classification. Epithets and other language intended to intimidate, unlawLine truncated
</div>
</div>
</div>
</template>
+81 -6
View File
@@ -8,6 +8,23 @@
Settings
</h2>
<div class="ui segment">
<h3>Change Password</h3>
<p>Create a new scratch pad. Old scratch pad will turn into a normal note.</p>
<div class="ui compact basic button shrinking" v-if="!showNewNoteConfirm" v-on:click="showNewNoteConfirm = true">
<i class="sync alternate reload icon"></i>
New Scratch Pad
</div>
<div v-if="showNewNoteConfirm" class="ui compact basic button shrinking" v-on:click="showNewNoteConfirm = false">
<i class="close icon"></i>
Cancel
</div>
<div v-if="showNewNoteConfirm" class="ui compact basic button shrinking" v-on:click="newQuickNote()">
<i class="green thumbs up icon"></i>
Confirm
</div>
</div>
<!-- Accent Color -->
<div class="ui segment">
<div class="ui grid">
@@ -65,20 +82,20 @@
<div class="five wide column">
<label>Current Password</label>
<div class="ui fluid input">
<input type="text" placeholder="Current Password">
<input v-model="change1" type="password" placeholder="Current Password">
</div>
</div>
<div class="five wide column">
<label>New Password</label>
<div class="ui fluid input">
<input type="text" placeholder="New Password">
<input v-model="change2" type="password" placeholder="New Password">
</div>
</div>
<div class="six wide column">
<label>Rereat New Password</label>
<div class="ui fluid action input">
<input type="text" placeholder="Repeat Password">
<div class="ui green button">
<input v-model="change3" type="password" placeholder="Repeat Password">
<div v-on:click="passwordChange()" class="ui button" :class="{'green':(change1.length > 0 && change2 == change3)}">
Change it!
</div>
</div>
@@ -98,7 +115,7 @@
</div>
</div>
<div class="eight wide column">
<div class="ui button">
<div class="ui button" v-on:click="revokeAllSessions()">
Log Out all other browsers
</div>
</div>
@@ -123,6 +140,7 @@
password: '',
qrCode: '',
verificationToken: '',
showNewNoteConfirm: false,
themeColors: [
'#21BA45', //Green
@@ -137,10 +155,26 @@
'#fbbd08', //Yellow
'#767676', //Grey
'#303030', //Black-almost
]
],
change1: '',
change2: '',
change3: '',
}
},
methods: {
newQuickNote(){
this.showNewNoteConfirm = true
axios.post('/api/quick-note/new')
.then( ({data}) => {
this.showNewNoteConfirm = false
this.$store.dispatch('fetchAndUpdateUserTotals')
this.$bus.$emit('notification', 'New Scratch Pad Created')
})
},
logout() {
this.$store.commit('destroyLoginToken')
this.$router.push('/')
@@ -176,6 +210,47 @@
//It failed
}
})
},
passwordChange(){
if(this.change1 == '' || this.change2 == '' || this.change3 == ''){
this.$bus.$emit('notification', 'All Password Fields Required')
return
}
if(this.change1 == this.change2){
this.$bus.$emit('notification', 'Old password matches new password')
return
}
if(this.change2 != this.change3){
this.$bus.$emit('notification', 'New Passwords do not match')
return
}
const postData = {
'currentPass':this.change1,
'newPass':this.change3
}
axios.post('/api/user/changepassword', postData)
.then(({data}) => {
if(data){
this.$bus.$emit('notification', 'Success: Password Changed')
this.change1 = ''
this.change2 = ''
this.change3 = ''
} else {
this.$bus.$emit('notification', 'Failed to change password')
this.change1 = ''
}
})
},
revokeAllSessions(){
axios.post('/api/user/revokesessions')
.then(({data}) => {
this.$bus.$emit('notification', 'All other active sessions revoked.')
})
}
}
}
+40 -23
View File
@@ -4,38 +4,55 @@
<div class="sixteen wide column"></div>
<div class="sixteen wide column" v-if="text.length > 0 || title.length > 0">
<div class="ui text container squire-box" :style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}">
<div class="ui text container">
<h1 v-if="title">{{title}}</h1>
<div class="ui segment" :style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}">
<div v-if="text" v-html="text"></div>
<h1 v-if="title">{{title}}</h1>
<div v-if="text" v-html="text" class="squire-box"></div>
</div>
</div>
</div>
<div class="sixteen wide column" v-if="!$store.getters.getLoggedIn">
<div class="ui text container">
<h2 class="ui header">
<img class="small-logo" loading="lazy" src="/api/static/assets/logo.svg" alt="Solid Scribe Logo">
<div class="content">
Solid Scribe is an easy, free, secure Note App
<div class="sub header">
Encrypted notes, only readable by you. Unless you share them.
<div class="ui segment">
<div class="ui grid">
<div class="three wide middle aligned center aligned column">
<img class="small-logo" loading="lazy" src="/api/static/assets/logo.svg" alt="Solid Scribe Logo">
</div>
<div class="thirteen wide column">
<!-- header -->
<h2 class="ui header">
<div class="content">
Solid Scribe is an easy, free, secure Note App
<div class="sub header">
Encrypted notes, only readable by you. Unless you share them.
</div>
</div>
</h2>
<!-- buttons -->
<div class="ui grid">
<div class="eight wide center aligned column">
<router-link class="ui compact green button" to="/login">
<i class="plug icon"></i>Sign Up
</router-link>
</div>
<div class="eight wide center aligned column">
<router-link class="ui compact green button" to="/">
<i class="comment outline icon"></i>
Learn More
</router-link>
</div>
</div>
</div>
</div>
</h2>
<div class="ui grid">
<div class="eight wide center aligned column">
<router-link class="ui compact green button" to="/login">
<i class="plug icon"></i>Sign Up
</router-link>
</div>
<div class="eight wide center aligned column">
<router-link class="ui compact green button" to="/">
<i class="comment outline icon"></i>
Learn More
</router-link>
</div>
</div>
</div>
</div>
@@ -99,7 +116,7 @@
<style type="text/css" scoped>
.small-logo {
width: 30px;
width: 100%;
height: auto;
}
</style>
+2
View File
@@ -7,6 +7,7 @@ let Auth = {}
const tokenSecretKey = process.env.JSON_KEY
//Creates session token
Auth.createToken = (userId, masterKey, pastId = null, pastCreatedDate = null) => {
return new Promise((resolve, reject) => {
@@ -42,6 +43,7 @@ Auth.createToken = (userId, masterKey, pastId = null, pastCreatedDate = null) =>
})
}
//Decodes session token
Auth.decodeToken = (token, request = null) => {
return new Promise((resolve, reject) => {
+1 -1
View File
@@ -263,7 +263,7 @@ let AuthTest = require('@helpers/Auth')
Auth.testTwoFactor()
Auth.test()
UserTest.keyPairTest('genMan16', '1', printResults)
UserTest.keyPairTest('genMan23', '1', printResults)
.then( ({testUserId, masterKey}) => NoteTest.test(testUserId, masterKey, printResults))
.then( message => {
if(printResults) console.log(message)
+16 -7
View File
@@ -10,19 +10,28 @@ QuickNote.get = (userId, masterKey) => {
db.promise()
.query(`
SELECT note.id FROM note WHERE quick_note = 1 AND user_id = ? LIMIT 1
`, [userId])
SELECT note.id FROM note WHERE quick_note = 1 AND user_id = ? LIMIT 1`, [userId])
.then((rows, fields) => {
//Quick Note is set, return note text
if(rows[0][0] != undefined){
let noteId = rows[0][0].id
Note.get(userId, noteId, masterKey)
.then( noteObject => {
return resolve(noteObject)
})
return resolve({'noteId':noteId})
} else {
return resolve(null)
//Or create a new note and get the id
let finalId = null
return Note.create(userId, 'Scratch Pad', '', masterKey)
.then(insertedId => {
finalId = insertedId
db.promise().query('UPDATE note SET quick_note = 1 WHERE id = ? AND user_id = ?',[insertedId, userId])
.then((rows, fields) => {
return resolve({'noteId':finalId})
})
})
}
+84 -3
View File
@@ -9,7 +9,7 @@ const speakeasy = require('speakeasy')
let User = module.exports = {}
const version = '3.1.3'
const version = '3.1.5'
//Login a user, if that user does not exist create them
//Issues login token
@@ -238,7 +238,7 @@ User.getCounts = (userId) => {
Object.assign(countTotals, rows[0][0]) //combine results
return db.promise().query('SELECT two_fa_enabled FROM user WHERE id = ?', [userId])
return db.promise().query('SELECT id AS quickNote FROM note WHERE quick_note = 1 AND user_id = ?', [userId])
}).then( (rows, fields) => {
@@ -432,6 +432,66 @@ User.getByUserName = (username) => {
})
}
User.changePassword = (userId, oldPass, newPass) => {
return new Promise((resolve, reject) => {
User.getMasterKey(userId, oldPass)
.then(masterKey => {
User.getPrivateKey(userId, masterKey)
.then(privateKey => {
//If success, user has correct password
// Generate new master pass, encrypt with new password
// const masterPassword = cs.createSmallSalt()
const salt = cs.createSmallSalt()
const encryptedMasterPassword = cs.encrypt(newPass, salt, masterKey)
const encryptedPrivateKey = cs.encrypt(masterKey, salt, privateKey)
db.promise()
.query(
'UPDATE user_key SET salt = ?, `key` = ?, private_key_encrypted = ? WHERE user_id = ? LIMIT 1',
[salt, encryptedMasterPassword, encryptedPrivateKey, userId]
).then((r,f) => {
//Create login using password
let shasum = crypto.createHash('sha512') //Prepare Hash
const saltString = shasum.digest('hex')
const passwordSalt = Buffer.from(saltString, 'binary') //Generate Salt hash
const iterations = 25000
crypto.pbkdf2(newPass, passwordSalt, iterations, 512, 'sha512', function(err, delivered_key) {
const deliveredPass = delivered_key.toString('hex')
db.promise().query('UPDATE user SET password = ?, salt = ? WHERE id = ? LIMIT 1', [deliveredPass, passwordSalt, userId])
.then((r,f) => {
return resolve(true)
})
})
})
})
})
.catch(error => {
resolve(false)
})
})
}
User.revokeActiveSessions = (userId, sessionId) => {
return new Promise((resolve, reject) => {
const userHash = cs.hash(String(userId)).toString('base64')
db.promise().query('DELETE FROM user_active_session WHERE user_hash = ? AND session_id != ?', [userHash, sessionId])
.then((r,f) => {
resolve(true)
})
})
}
User.deleteUser = (userId, password) => {
//Verify user is correct by decryptig master key with password
@@ -471,6 +531,7 @@ User.keyPairTest = (testUserName = 'genMan', password = '1', printResults) => {
const randomUsername = Math.random().toString(36).substring(2, 15);
const randomPassword = '1'
const secondPassword = '2'
User.register(testUserName, password)
.then( ({ token, userId }) => {
@@ -478,7 +539,7 @@ User.keyPairTest = (testUserName = 'genMan', password = '1', printResults) => {
if(printResults) console.log('Test: Register User '+testUserName+' - Pass')
return User.getMasterKey(testUserId, password)
return User.getMasterKey(testUserId, password)
})
.then(newMasterKey => {
masterKey = newMasterKey
@@ -510,6 +571,26 @@ User.keyPairTest = (testUserName = 'genMan', password = '1', printResults) => {
if(printResults) console.log('Test: Login New User - Pass')
return User.changePassword(testUserId, randomPassword, secondPassword)
})
.then(passwordChangeResults => {
if(printResults) console.log('Test: Password Change - ', passwordChangeResults?'Pass':'Fail')
return User.login(testUserName, secondPassword)
})
.then(reLogin => {
if(printResults) console.log('Test: Login With new Password - Pass')
return User.getMasterKey(testUserId, secondPassword)
})
.then(newMasterKey => {
masterKey = newMasterKey
resolve({testUserId, masterKey})
})
})
+1 -2
View File
@@ -6,9 +6,8 @@ let QuickNote = require('@models/QuickNote');
let userId = null
let masterKey = null
// middleware that is specific to this router
router.use(function setUserId (req, res, next) {
if(userId = req.headers.userId){
if(req.headers.userId){
userId = req.headers.userId
masterKey = req.headers.masterKey
}
+19
View File
@@ -41,6 +41,25 @@ router.post('/register', function (req, res) {
})
})
// change password
router.post('/changepassword', function (req, res) {
User.changePassword(req.headers.userId, req.body.currentPass, req.body.newPass)
.then( returnData => {
res.send(returnData)
})
})
//Revoke all active session keys for user
router.post('/revokesessions', function(req, res) {
User.revokeActiveSessions(req.headers.userId, req.headers.sessionId)
.then( returnData => {
res.send(returnData)
})
})
// fetch counts of users notes
router.post('/totals', function (req, res) {
User.getCounts(req.headers.userId)