Compare commits
2 Commits
cca89a60d8
...
e7d1cc7bc9
Author | SHA1 | Date | |
---|---|---|---|
|
e7d1cc7bc9 | ||
|
47fff0e1ee |
Binary file not shown.
Before Width: | Height: | Size: 6.7 KiB |
@ -97,6 +97,12 @@ export default {
|
|||||||
//Detect if user is on a mobile browser and set a flag in store
|
//Detect if user is on a mobile browser and set a flag in store
|
||||||
this.$store.commit('detectIsUserOnMobile')
|
this.$store.commit('detectIsUserOnMobile')
|
||||||
|
|
||||||
|
//Set Main theme color
|
||||||
|
const accentColor = localStorage.getItem('main-accent')
|
||||||
|
if(accentColor){
|
||||||
|
document.documentElement.style.setProperty('--main-accent', accentColor)
|
||||||
|
}
|
||||||
|
|
||||||
//Set color theme based on local storage
|
//Set color theme based on local storage
|
||||||
const themeNumber = localStorage.getItem('nightMode')
|
const themeNumber = localStorage.getItem('nightMode')
|
||||||
if(themeNumber != null){
|
if(themeNumber != null){
|
||||||
|
@ -4,6 +4,10 @@ const helpers = {}
|
|||||||
|
|
||||||
helpers.timeAgo = (time) => {
|
helpers.timeAgo = (time) => {
|
||||||
|
|
||||||
|
if(time == null){
|
||||||
|
time = Math.round(time/1000)
|
||||||
|
}
|
||||||
|
|
||||||
if(time.toString().length >= 13){
|
if(time.toString().length >= 13){
|
||||||
time = Math.round(time/1000)
|
time = Math.round(time/1000)
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,8 @@
|
|||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
|
||||||
--main-accent: #16ab39;
|
/*main accent for all buttons, icons and logos*/
|
||||||
|
--main-accent: #21BA45;
|
||||||
|
|
||||||
/*theme colors */
|
/*theme colors */
|
||||||
--body_bg_color: #f5f6f7;
|
--body_bg_color: #f5f6f7;
|
||||||
@ -85,6 +86,8 @@ body {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.ui.form input:not([type]),
|
.ui.form input:not([type]),
|
||||||
.ui.form input:not([type]):focus,
|
.ui.form input:not([type]):focus,
|
||||||
.ui.form textarea:not([type]),
|
.ui.form textarea:not([type]),
|
||||||
@ -93,6 +96,21 @@ body {
|
|||||||
background-color: var(--small_element_bg_color);
|
background-color: var(--small_element_bg_color);
|
||||||
border-color: var(--dark_border_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 {
|
.ui.basic.label, .ui.header, .ui.header div.sub.header {
|
||||||
color: var(--text_color);
|
color: var(--text_color);
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
@ -105,7 +123,7 @@ div.ui.basic.green.label {
|
|||||||
background-color: var(--small_element_bg_color) !important;
|
background-color: var(--small_element_bg_color) !important;
|
||||||
}
|
}
|
||||||
.ui.basic.button, .ui.basic.buttons .button {
|
.ui.basic.button, .ui.basic.buttons .button {
|
||||||
background-color: var(--small_element_bg_color) !important;
|
background-color: var(--small_element_bg_color);
|
||||||
color: var(--text_color) !important;
|
color: var(--text_color) !important;
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
border-color: var(--dark_border_color) !important;
|
border-color: var(--dark_border_color) !important;
|
||||||
@ -125,6 +143,24 @@ div.ui.basic.green.label {
|
|||||||
color: var(--text_color) !important;
|
color: var(--text_color) !important;
|
||||||
border-color: var(--dark_border_color) !important;
|
border-color: var(--dark_border_color) !important;
|
||||||
}
|
}
|
||||||
|
/*Overwrites for modifiable theme color */
|
||||||
|
i.green.icon.icon.icon.icon {
|
||||||
|
color: var(--main-accent);
|
||||||
|
}
|
||||||
|
.ui.green.buttons, .ui.green.button, .ui.green.button:hover {
|
||||||
|
background-color: var(--main-accent);
|
||||||
|
}
|
||||||
|
.ui.basic.green.button, .ui.basic.green.buttons .button:hover, .ui.basic.green.button:hover, .ui.basic.green.button:focus {
|
||||||
|
box-shadow: var(--main-accent) 0px 0px 0px 1px inset;
|
||||||
|
}
|
||||||
|
.ui.green.labels .label, .ui.ui.ui.green.label {
|
||||||
|
background-color: var(--main-accent);
|
||||||
|
border-color: var(--main-accent);
|
||||||
|
}
|
||||||
|
.ui.grid > .green.row, .ui.grid > .green.column, .ui.grid > .row > .green.column {
|
||||||
|
background-color: var(--main-accent);
|
||||||
|
}
|
||||||
|
|
||||||
/* OVERWRITE DEFAULT SEMANTIC STYLES FOR CUSTOM/NIGHT MODES*/
|
/* OVERWRITE DEFAULT SEMANTIC STYLES FOR CUSTOM/NIGHT MODES*/
|
||||||
|
|
||||||
/*//
|
/*//
|
||||||
@ -235,7 +271,7 @@ div.ui.basic.green.label {
|
|||||||
/*border-bottom: 1px solid #ccc;*/
|
/*border-bottom: 1px solid #ccc;*/
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
scrollbar-color: transparent transparent;
|
scrollbar-color: transparent transparent;
|
||||||
caret-color: #21BA45;
|
caret-color: var(--main-accent);
|
||||||
}
|
}
|
||||||
.squire-box::selection,
|
.squire-box::selection,
|
||||||
.squire-box::-moz-selection {
|
.squire-box::-moz-selection {
|
||||||
@ -253,7 +289,7 @@ div.ui.basic.green.label {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.night-mode .note-card-text i:not(.icon),
|
.night-mode .note-card-text i:not(.icon),
|
||||||
.night-mode .squire-box i {
|
.night-mode .squire-box i:not(.icon) {
|
||||||
background-color: rgba(255, 255, 255, 0.2);
|
background-color: rgba(255, 255, 255, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,9 +358,76 @@ div.ui.basic.green.label {
|
|||||||
|
|
||||||
font-family: 'Icons';
|
font-family: 'Icons';
|
||||||
content: "\f058";
|
content: "\f058";
|
||||||
color: #21BA45;
|
color: var(--main-accent);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.note-title-display-card .divide,
|
||||||
|
.squire-box .divide {
|
||||||
|
width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
height: 2px;
|
||||||
|
background-color: var(--main-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
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;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
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%;
|
||||||
|
display: inline-block;
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-table > span,
|
||||||
|
.t-table > div {
|
||||||
|
display: flex; /* aligns all child elements (flex items) in a row */
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-table > span > span,
|
||||||
|
.t-table > div > div {
|
||||||
|
flex: 1; /* distributes space on the line equally among items */
|
||||||
|
border: 1px solid #DDD;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* adjust checkboxes for mobile. Make them a little bigger, easier to click */
|
/* adjust checkboxes for mobile. Make them a little bigger, easier to click */
|
||||||
@media only screen and (max-width: 740px) {
|
@media only screen and (max-width: 740px) {
|
||||||
|
|
||||||
@ -365,7 +468,7 @@ div.ui.basic.green.label {
|
|||||||
|
|
||||||
font-family: 'Icons';
|
font-family: 'Icons';
|
||||||
content: "\f058";
|
content: "\f058";
|
||||||
color: #21BA45;
|
color: var(--main-accent);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1096,6 +1096,9 @@ var moveRangeBoundariesUpTree = function ( range, startMax, endMax, root ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while ( true ) {
|
while ( true ) {
|
||||||
|
if ( endContainer === endMax || endContainer === root ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if ( maySkipBR &&
|
if ( maySkipBR &&
|
||||||
endContainer.nodeType !== TEXT_NODE &&
|
endContainer.nodeType !== TEXT_NODE &&
|
||||||
endContainer.childNodes[ endOffset ] &&
|
endContainer.childNodes[ endOffset ] &&
|
||||||
@ -1103,9 +1106,7 @@ var moveRangeBoundariesUpTree = function ( range, startMax, endMax, root ) {
|
|||||||
endOffset += 1;
|
endOffset += 1;
|
||||||
maySkipBR = false;
|
maySkipBR = false;
|
||||||
}
|
}
|
||||||
if ( endContainer === endMax ||
|
if ( endOffset !== getLength( endContainer ) ) {
|
||||||
endContainer === root ||
|
|
||||||
endOffset !== getLength( endContainer ) ) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
parent = endContainer.parentNode;
|
parent = endContainer.parentNode;
|
||||||
@ -1117,6 +1118,20 @@ var moveRangeBoundariesUpTree = function ( range, startMax, endMax, root ) {
|
|||||||
range.setEnd( endContainer, endOffset );
|
range.setEnd( endContainer, endOffset );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var moveRangeBoundaryOutOf = function ( range, nodeName, root ) {
|
||||||
|
var parent = getNearest( range.endContainer, root, 'A' );
|
||||||
|
if ( parent ) {
|
||||||
|
var clone = range.cloneRange();
|
||||||
|
parent = parent.parentNode;
|
||||||
|
moveRangeBoundariesUpTree( clone, parent, parent, root );
|
||||||
|
if ( clone.endContainer === parent ) {
|
||||||
|
range.setStart( clone.endContainer, clone.endOffset );
|
||||||
|
range.setEnd( clone.endContainer, clone.endOffset );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return range;
|
||||||
|
};
|
||||||
|
|
||||||
// Returns the first block at least partially contained by the range,
|
// Returns the first block at least partially contained by the range,
|
||||||
// or null if no block is contained by the range.
|
// or null if no block is contained by the range.
|
||||||
var getStartBlockOfRange = function ( range, root ) {
|
var getStartBlockOfRange = function ( range, root ) {
|
||||||
@ -1285,10 +1300,13 @@ var onKey = function ( event ) {
|
|||||||
if ( event.altKey ) { modifiers += 'alt-'; }
|
if ( event.altKey ) { modifiers += 'alt-'; }
|
||||||
if ( event.ctrlKey ) { modifiers += 'ctrl-'; }
|
if ( event.ctrlKey ) { modifiers += 'ctrl-'; }
|
||||||
if ( event.metaKey ) { modifiers += 'meta-'; }
|
if ( event.metaKey ) { modifiers += 'meta-'; }
|
||||||
|
if ( event.shiftKey ) { modifiers += 'shift-'; }
|
||||||
}
|
}
|
||||||
// However, on Windows, shift-delete is apparently "cut" (WTF right?), so
|
// However, on Windows, shift-delete is apparently "cut" (WTF right?), so
|
||||||
// we want to let the browser handle shift-delete.
|
// we want to let the browser handle shift-delete in this situation.
|
||||||
if ( event.shiftKey ) { modifiers += 'shift-'; }
|
if ( isWin && event.shiftKey && key === 'delete' ) {
|
||||||
|
modifiers += 'shift-';
|
||||||
|
}
|
||||||
|
|
||||||
key = modifiers + key;
|
key = modifiers + key;
|
||||||
|
|
||||||
@ -1465,12 +1483,7 @@ var handleEnter = function ( self, shiftKey, range ) {
|
|||||||
// just play it safe and insert a <br>.
|
// just play it safe and insert a <br>.
|
||||||
if ( !block || shiftKey || /^T[HD]$/.test( block.nodeName ) ) {
|
if ( !block || shiftKey || /^T[HD]$/.test( block.nodeName ) ) {
|
||||||
// If inside an <a>, move focus out
|
// If inside an <a>, move focus out
|
||||||
parent = getNearest( range.endContainer, root, 'A' );
|
moveRangeBoundaryOutOf( range, 'A', root );
|
||||||
if ( parent ) {
|
|
||||||
parent = parent.parentNode;
|
|
||||||
moveRangeBoundariesUpTree( range, parent, parent, root );
|
|
||||||
range.collapse( false );
|
|
||||||
}
|
|
||||||
insertNodeInRange( range, self.createElement( 'BR' ) );
|
insertNodeInRange( range, self.createElement( 'BR' ) );
|
||||||
range.collapse( false );
|
range.collapse( false );
|
||||||
self.setSelection( range );
|
self.setSelection( range );
|
||||||
@ -1821,16 +1834,45 @@ if ( !isMac ) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const changeIndentationLevel = function ( methodIfInQuote, methodIfInList ) {
|
||||||
|
return function ( self, event ) {
|
||||||
|
event.preventDefault();
|
||||||
|
var path = self.getPath();
|
||||||
|
if ( /(?:^|>)BLOCKQUOTE/.test( path ) ||
|
||||||
|
!/(?:^|>)[OU]L/.test( path ) ) {
|
||||||
|
self[ methodIfInQuote ]();
|
||||||
|
} else {
|
||||||
|
self[ methodIfInList ]();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleList = function ( listRegex, methodIfNotInList ) {
|
||||||
|
return function ( self, event ) {
|
||||||
|
event.preventDefault();
|
||||||
|
var path = self.getPath();
|
||||||
|
if ( !listRegex.test( path ) ) {
|
||||||
|
self[ methodIfNotInList ]();
|
||||||
|
} else {
|
||||||
|
self.removeList();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
keyHandlers[ ctrlKey + 'b' ] = mapKeyToFormat( 'B' );
|
keyHandlers[ ctrlKey + 'b' ] = mapKeyToFormat( 'B' );
|
||||||
keyHandlers[ ctrlKey + 'i' ] = mapKeyToFormat( 'I' );
|
keyHandlers[ ctrlKey + 'i' ] = mapKeyToFormat( 'I' );
|
||||||
keyHandlers[ ctrlKey + 'u' ] = mapKeyToFormat( 'U' );
|
keyHandlers[ ctrlKey + 'u' ] = mapKeyToFormat( 'U' );
|
||||||
keyHandlers[ ctrlKey + 'shift-7' ] = mapKeyToFormat( 'S' );
|
keyHandlers[ ctrlKey + 'shift-7' ] = mapKeyToFormat( 'S' );
|
||||||
keyHandlers[ ctrlKey + 'shift-5' ] = mapKeyToFormat( 'SUB', { tag: 'SUP' } );
|
keyHandlers[ ctrlKey + 'shift-5' ] = mapKeyToFormat( 'SUB', { tag: 'SUP' } );
|
||||||
keyHandlers[ ctrlKey + 'shift-6' ] = mapKeyToFormat( 'SUP', { tag: 'SUB' } );
|
keyHandlers[ ctrlKey + 'shift-6' ] = mapKeyToFormat( 'SUP', { tag: 'SUB' } );
|
||||||
keyHandlers[ ctrlKey + 'shift-8' ] = mapKeyTo( 'makeUnorderedList' );
|
keyHandlers[ ctrlKey + 'shift-8' ] =
|
||||||
keyHandlers[ ctrlKey + 'shift-9' ] = mapKeyTo( 'makeOrderedList' );
|
toggleList( /(?:^|>)UL/, 'makeUnorderedList' );
|
||||||
keyHandlers[ ctrlKey + '[' ] = mapKeyTo( 'decreaseQuoteLevel' );
|
keyHandlers[ ctrlKey + 'shift-9' ] =
|
||||||
keyHandlers[ ctrlKey + ']' ] = mapKeyTo( 'increaseQuoteLevel' );
|
toggleList( /(?:^|>)OL/, 'makeOrderedList' );
|
||||||
|
keyHandlers[ ctrlKey + '[' ] =
|
||||||
|
changeIndentationLevel( 'decreaseQuoteLevel', 'decreaseListLevel' );
|
||||||
|
keyHandlers[ ctrlKey + ']' ] =
|
||||||
|
changeIndentationLevel( 'increaseQuoteLevel', 'increaseListLevel' );
|
||||||
keyHandlers[ ctrlKey + 'd' ] = mapKeyTo( 'toggleCode' );
|
keyHandlers[ ctrlKey + 'd' ] = mapKeyTo( 'toggleCode' );
|
||||||
keyHandlers[ ctrlKey + 'y' ] = mapKeyTo( 'redo' );
|
keyHandlers[ ctrlKey + 'y' ] = mapKeyTo( 'redo' );
|
||||||
keyHandlers[ ctrlKey + 'z' ] = mapKeyTo( 'undo' );
|
keyHandlers[ ctrlKey + 'z' ] = mapKeyTo( 'undo' );
|
||||||
@ -4417,6 +4459,12 @@ proto.insertHTML = function ( html, isPaste ) {
|
|||||||
this._docWasChanged();
|
this._docWasChanged();
|
||||||
}
|
}
|
||||||
range.collapse( false );
|
range.collapse( false );
|
||||||
|
|
||||||
|
// After inserting the fragment, check whether the cursor is inside
|
||||||
|
// an <a> element and if so if there is an equivalent cursor
|
||||||
|
// position after the <a> element. If there is, move it there.
|
||||||
|
moveRangeBoundaryOutOf( range, 'A', root );
|
||||||
|
|
||||||
this._ensureBottomLine();
|
this._ensureBottomLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4947,4 +4995,4 @@ if ( typeof exports === 'object' ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}( document ) );
|
}( document ) );
|
||||||
|
@ -182,7 +182,6 @@
|
|||||||
openNote(){
|
openNote(){
|
||||||
const noteId = this.item.note_id
|
const noteId = this.item.note_id
|
||||||
this.$router.push('/notes/open/'+noteId)
|
this.$router.push('/notes/open/'+noteId)
|
||||||
this.$bus.$emit('open_note', noteId)
|
|
||||||
},
|
},
|
||||||
openEditAttachments(){
|
openEditAttachments(){
|
||||||
const noteId = this.item.note_id
|
const noteId = this.item.note_id
|
||||||
|
@ -24,9 +24,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeMount(){
|
beforeMount(){
|
||||||
this.$bus.$on('reset_fast_filters', () => {
|
// this.$bus.$on('reset_fast_filters', () => {
|
||||||
this.orderString = 'Order by Last Edited'
|
// this.orderString = 'Order by Last Edited'
|
||||||
})
|
// })
|
||||||
},
|
},
|
||||||
methods:{
|
methods:{
|
||||||
displayString(){
|
displayString(){
|
||||||
|
@ -2,30 +2,31 @@
|
|||||||
|
|
||||||
.popup-body {
|
.popup-body {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 15px;
|
top: 15px;
|
||||||
left: 15px;
|
left: 15px;
|
||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
max-width: calc(100% - 20px);
|
max-width: calc(100% - 30px);
|
||||||
z-index: 1002;
|
z-index: 1002;
|
||||||
|
|
||||||
border-top: 2px solid #21ba45;
|
|
||||||
box-shadow: 0px 0px 5px 2px rgba(140,140,140,1);
|
box-shadow: 0px 0px 5px 2px rgba(140,140,140,1);
|
||||||
border-top-right-radius: 4px;
|
border-radius: 4px;
|
||||||
border-top-left-radius: 4px;
|
|
||||||
|
color: white;
|
||||||
|
background-color: var(--main-accent);
|
||||||
}
|
}
|
||||||
.popup-row {
|
.popup-row {
|
||||||
padding: 1em 5px;
|
padding: 1em 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
.popup-row > span {
|
.popup-row > span {
|
||||||
width: calc(100% - 50px);
|
/*width: calc(100% - 50px);*/
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-align: center;
|
text-align: left;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 0 10px 0;
|
padding: 0 10px 0;
|
||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
.popup-row + .popup-row {
|
.popup-row + .popup-row {
|
||||||
border-top: 1px solid #FFF;
|
border-top: 1px solid #FFF;
|
||||||
@ -36,12 +37,10 @@
|
|||||||
}
|
}
|
||||||
@keyframes slide-in-bottom {
|
@keyframes slide-in-bottom {
|
||||||
0% {
|
0% {
|
||||||
transform: translateY(1000px);
|
transform: translateY(-1000px);
|
||||||
opacity: 0;
|
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
transform: translateY(0);
|
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>
|
</style>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="popup-body slide-in-bottom" v-on:click="dismiss" v-if="notifications.length > 0">
|
<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">
|
<div class="popup-row" v-for="item in notifications">
|
||||||
<span>{{ item }}</span>
|
<div class="meter">
|
||||||
|
<span><span class="progress"></span></span>
|
||||||
|
</div>
|
||||||
|
<span><i class="small info circle icon"></i>{{ item }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -94,9 +125,9 @@
|
|||||||
},
|
},
|
||||||
mounted(){
|
mounted(){
|
||||||
|
|
||||||
// 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')
|
// this.$bus.$emit('notification', 'Password Protection Removed your life is exposed to the internet')
|
||||||
// this.$bus.$emit('notification', 'Password Protection Removed')
|
// this.$bus.$emit('notification', 'Password Protection Removed everyone can see everything')
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -105,7 +136,7 @@
|
|||||||
clearTimeout(this.totalTimeout)
|
clearTimeout(this.totalTimeout)
|
||||||
this.totalTimeout = setTimeout(() => {
|
this.totalTimeout = setTimeout(() => {
|
||||||
this.dismiss()
|
this.dismiss()
|
||||||
}, 4000)
|
}, 3000)
|
||||||
},
|
},
|
||||||
dismiss(){
|
dismiss(){
|
||||||
this.notifications = []
|
this.notifications = []
|
||||||
|
@ -19,9 +19,10 @@
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
.menu-logo-display {
|
.menu-logo-display {
|
||||||
width: 25px;
|
width: 27px;
|
||||||
margin: 5px 0 0 42px;
|
margin: 5px 0 0 41px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-item {
|
.menu-item {
|
||||||
@ -79,15 +80,17 @@
|
|||||||
background-color: var(--small_element_bg_color);
|
background-color: var(--small_element_bg_color);
|
||||||
border-bottom: 1px solid;
|
border-bottom: 1px solid;
|
||||||
border-color: var(--border_color);
|
border-color: var(--border_color);
|
||||||
padding: 5px 1rem 5px;
|
/*padding: 5px 1rem 5px;*/
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
}
|
}
|
||||||
.place-holder {
|
.place-holder {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
}
|
}
|
||||||
.top-menu-bar img {
|
.logo-display {
|
||||||
width: 30px;
|
width: 27px;
|
||||||
height: 30px;
|
height: auto;
|
||||||
}
|
}
|
||||||
.version-display {
|
.version-display {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -101,6 +104,19 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mobile-button {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 2em;
|
||||||
|
padding: 6px 3px 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.mobile-button.active {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.mobile-button i {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -110,45 +126,51 @@
|
|||||||
|
|
||||||
<!-- collapsed menu, appears as a bar -->
|
<!-- collapsed menu, appears as a bar -->
|
||||||
<div class="top-menu-bar" v-if="(collapsed || mobile) && !menuOpen">
|
<div class="top-menu-bar" v-if="(collapsed || mobile) && !menuOpen">
|
||||||
<div class="ui grid">
|
|
||||||
|
|
||||||
<div class="seven wide column">
|
|
||||||
<div class="ui large basic compact icon button" v-on:click="collapseMenu">
|
|
||||||
<i class="green bars icon"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- <router-link v-if="loggedIn" class="ui large basic compact icon button" to="/notes" v-on:click.native="emitReloadEvent()">
|
|
||||||
<i class="green home icon"></i>
|
|
||||||
</router-link> -->
|
|
||||||
|
|
||||||
<router-link v-if="loggedIn" class="ui basic icon button" exact-active-class="active" to="/attachments">
|
|
||||||
<i class="open folder outline icon"></i>
|
|
||||||
</router-link>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="two wide center aligned bottom aligned column">
|
|
||||||
<img loading="lazy" src="/api/static/assets/logo.svg" alt="Solid Scribe Logo">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="seven wide right aligned column">
|
|
||||||
|
|
||||||
<div v-on:click="toggleNightMode" class="ui large basic compact icon button">
|
|
||||||
<i class="green moon outline icon"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- mobile create note button -->
|
|
||||||
<span v-if="loggedIn">
|
|
||||||
<span v-if="!disableNewNote" @click="createNote" class="ui large green compact icon button">
|
|
||||||
<i class="plus icon"></i>
|
|
||||||
</span>
|
|
||||||
<span v-if="disableNewNote" class="ui large basic compact icon button">
|
|
||||||
<i class="grey plus icon"></i>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div class="mobile-button">
|
||||||
|
<i class="green link bars icon" v-on:click="collapseMenu"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mobile-button"></div>
|
||||||
|
|
||||||
|
<!-- 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)" />
|
||||||
|
</router-link>
|
||||||
|
|
||||||
|
<router-link v-if="loggedIn" class="mobile-button" exact-active-class="active" to="/attachments">
|
||||||
|
<i class="green open folder outline icon"></i>
|
||||||
|
</router-link>
|
||||||
|
|
||||||
|
<div class="mobile-button"></div>
|
||||||
|
|
||||||
|
<!-- mobile create note button -->
|
||||||
|
<span v-if="loggedIn">
|
||||||
|
<span v-if="!disableNewNote" @click="createNote" class="mobile-button">
|
||||||
|
<i class="green plus icon"></i>
|
||||||
|
</span>
|
||||||
|
<span v-if="disableNewNote" class="mobile-button">
|
||||||
|
<i class="grey plus icon"></i>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="shade" v-if="mobile && !collapsed" v-on:click="collapseMenu"></div>
|
<div class="shade" v-if="mobile && !collapsed" v-on:click="collapseMenu"></div>
|
||||||
@ -159,10 +181,8 @@
|
|||||||
<div class="global-menu" v-if="!collapsed" v-on:click="menuClicked">
|
<div class="global-menu" v-if="!collapsed" v-on:click="menuClicked">
|
||||||
|
|
||||||
<div class="menu-section" v-on:click="collapseMenu">
|
<div class="menu-section" v-on:click="collapseMenu">
|
||||||
<!-- <div class="menu-item menu-button" > -->
|
<i class="white angle left icon"></i>
|
||||||
<i class="white angle left icon"></i>
|
<logo class="menu-logo-display" color="var(--main-accent)" />
|
||||||
<img class="menu-logo-display" loading="lazy" src="/api/static/assets/logo.svg" alt="Solid Scribe Logo">
|
|
||||||
<!-- </div> -->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="menu-section" v-if="loggedIn">
|
<div class="menu-section" v-if="loggedIn">
|
||||||
@ -208,9 +228,26 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="menu-section" v-if="loggedIn">
|
<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
|
<i class="sticky note outline icon"></i>Scratch Pad
|
||||||
</router-link>
|
</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>
|
||||||
|
|
||||||
<div class="menu-section" v-if="!loggedIn">
|
<div class="menu-section" v-if="!loggedIn">
|
||||||
@ -236,14 +273,14 @@
|
|||||||
|
|
||||||
<div class="menu-section">
|
<div class="menu-section">
|
||||||
<router-link class="menu-item menu-button" exact-active-class="active" to="/help">
|
<router-link class="menu-item menu-button" exact-active-class="active" to="/help">
|
||||||
<i class="question circle outline icon"></i>Help
|
<i class="question circle outline icon"></i>Help | Terms
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="menu-section" v-if="loggedIn" :data-tooltip="`Logout ${this.$store.getters.getUsername}`" data-inverted="" data-position="right center">
|
<div class="menu-section" v-if="loggedIn" :data-tooltip="`Settings for ${this.$store.getters.getUsername}`" data-inverted="" data-position="right center">
|
||||||
<div v-on:click="destroyLoginToken" class="menu-item menu-button">
|
<router-link class="menu-item menu-button" exact-active-class="active" to="/settings">
|
||||||
<i v-if="userIcon" class="user outline icon"></i>{{ usernameDisplay }}
|
<i v-if="userIcon" class="cog icon"></i>{{ usernameDisplay }}
|
||||||
</div>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@ -264,6 +301,7 @@
|
|||||||
components: {
|
components: {
|
||||||
'search-input': require('@/components/SearchInput.vue').default,
|
'search-input': require('@/components/SearchInput.vue').default,
|
||||||
'counter':require('@/components/AnimatedCounterComponent.vue').default,
|
'counter':require('@/components/AnimatedCounterComponent.vue').default,
|
||||||
|
'logo':require('@/components/LogoComponent.vue').default,
|
||||||
},
|
},
|
||||||
data: function(){
|
data: function(){
|
||||||
return {
|
return {
|
||||||
@ -274,10 +312,14 @@
|
|||||||
disableNewNote: false,
|
disableNewNote: false,
|
||||||
menuOpen: true,
|
menuOpen: true,
|
||||||
userIcon: true,
|
userIcon: true,
|
||||||
|
resizeDebounce: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeCreate: function(){
|
beforeMount(){
|
||||||
|
window.addEventListener('resize', this.resizeEventHandler)
|
||||||
|
},
|
||||||
|
beforeDestroy(){
|
||||||
|
window.removeEventListener('resize', this.resizeEventHandler)
|
||||||
},
|
},
|
||||||
mounted: function(){
|
mounted: function(){
|
||||||
this.mobile = this.$store.getters.getIsUserOnMobile
|
this.mobile = this.$store.getters.getIsUserOnMobile
|
||||||
@ -291,6 +333,8 @@
|
|||||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||||
this.version = localStorage.getItem('currentVersion')
|
this.version = localStorage.getItem('currentVersion')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.resizeEventHandler() //Trigger resize event
|
||||||
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -316,6 +360,32 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
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)
|
||||||
|
},
|
||||||
menuClicked(){
|
menuClicked(){
|
||||||
//Collapse menu when item is clicked in mobile
|
//Collapse menu when item is clicked in mobile
|
||||||
if(this.mobile && !this.collapsed){
|
if(this.mobile && !this.collapsed){
|
||||||
@ -334,28 +404,22 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
createNote(event){
|
createNote(event){
|
||||||
const title = ''
|
|
||||||
this.disableNewNote = true
|
this.disableNewNote = true
|
||||||
|
|
||||||
axios.post('/api/note/create', {title})
|
axios.post('/api/note/create', {title:''})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
|
||||||
if(response.data && response.data.id){
|
if(response.data && response.data.id){
|
||||||
//Redirect to note page if user is not on it
|
|
||||||
this.$bus.$emit('open_note', response.data.id)
|
//Push new note to url and it will open
|
||||||
|
this.$router.push('/notes/open/'+response.data.id)
|
||||||
|
|
||||||
this.disableNewNote = false
|
this.disableNewNote = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => { this.$bus.$emit('notification', 'Failed to create note') })
|
.catch(error => { this.$bus.$emit('notification', 'Failed to create note') })
|
||||||
},
|
},
|
||||||
destroyLoginToken() {
|
|
||||||
axios.post('/api/user/logout')
|
|
||||||
setTimeout(() => {
|
|
||||||
this.$bus.$emit('notification', 'Logged Out')
|
|
||||||
this.$store.commit('destroyLoginToken')
|
|
||||||
this.$router.push('/')
|
|
||||||
}, 200)
|
|
||||||
},
|
|
||||||
toggleNightMode(){
|
toggleNightMode(){
|
||||||
this.$store.commit('toggleNightMode')
|
this.$store.commit('toggleNightMode')
|
||||||
},
|
},
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="loading-container">
|
<div class="loading-container">
|
||||||
<svg version="1.1" id="L6" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
|
<svg version="1.1" id="L6" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
|
||||||
<rect fill="none" :stroke="$store.getters.getIsNightMode > 0 ? '#FFF':'#16ab39'" stroke-width="4" x="25" y="25" width="50" height="50" rx="5">
|
<rect fill="none" :stroke="$store.getters.getIsNightMode > 0 ? '#FFF':'var(--main-accent)'" stroke-width="4" x="25" y="25" width="50" height="50" rx="5">
|
||||||
<animateTransform
|
<animateTransform
|
||||||
attributeName="transform"
|
attributeName="transform"
|
||||||
dur="0.5s"
|
dur="0.5s"
|
||||||
@ -12,7 +12,7 @@
|
|||||||
attributeType="XML"
|
attributeType="XML"
|
||||||
begin="rectBox.end"/>
|
begin="rectBox.end"/>
|
||||||
</rect>
|
</rect>
|
||||||
<rect x="25" y="25" :fill="$store.getters.getIsNightMode > 0 ? '#FFF':'#16ab39'" width="50" height="50">
|
<rect x="25" y="25" :fill="$store.getters.getIsNightMode > 0 ? '#FFF':'var(--main-accent)'" width="50" height="50">
|
||||||
<animate
|
<animate
|
||||||
attributeName="height"
|
attributeName="height"
|
||||||
dur="1.3s"
|
dur="1.3s"
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div v-on:keyup.enter="login()">
|
<div v-on:keyup.enter="login()">
|
||||||
@ -14,6 +15,11 @@
|
|||||||
<input v-model="password" type="password" name="password" placeholder="Password">
|
<input v-model="password" type="password" name="password" placeholder="Password">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field" v-if="require2FA">
|
||||||
|
<div class="ui input">
|
||||||
|
<input v-model="authToken" ref="authForm" type="text" name="authToken" placeholder="Authorization Token">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="sixteen wide field">
|
<div class="sixteen wide field">
|
||||||
<div class="ui fluid buttons">
|
<div class="ui fluid buttons">
|
||||||
<div :class="{ 'disabled':(username.length == 0 || password.length == 0)}" v-on:click="login()" class="ui green button">
|
<div :class="{ 'disabled':(username.length == 0 || password.length == 0)}" v-on:click="login()" class="ui green button">
|
||||||
@ -27,34 +33,54 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sixteen wide column">
|
||||||
|
<span class="small-terms">
|
||||||
|
By signing up you agree to Solid Scribe's
|
||||||
|
<router-link to="/help">
|
||||||
|
Terms of Use
|
||||||
|
</router-link>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Thin form display -->
|
<!-- Thin form display -->
|
||||||
<div v-if="thin" class="ui small form">
|
<div v-if="thin" class="ui small form">
|
||||||
<div class="fields">
|
<div class="equal width fields">
|
||||||
<div class="four wide field">
|
<div class="field">
|
||||||
<div class="ui input">
|
<div class="ui input">
|
||||||
<input ref="nameForm" v-model="username" type="text" name="email" placeholder="Username or E-mail">
|
<input ref="nameForm" v-model="username" type="text" name="email" placeholder="Username or E-mail">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="four wide field">
|
<div class="field">
|
||||||
<div class="ui input">
|
<div class="ui input">
|
||||||
<input v-model="password" type="password" name="password" placeholder="Password">
|
<input v-model="password" type="password" name="password" placeholder="Password">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="four wide field">
|
<div class="field" v-if="require2FA">
|
||||||
|
<div class="ui input">
|
||||||
|
<input v-model="authToken" ref="authForm" type="text" name="authToken" placeholder="Authorization Token">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- hide this field if someone is logging in with 2FA -->
|
||||||
|
<div class="field" v-if="!require2FA">
|
||||||
<div v-on:click="register()" class="ui fluid green button">
|
<div v-on:click="register()" class="ui fluid green button">
|
||||||
<i class="plug icon"></i>
|
<i class="plug icon"></i>
|
||||||
Sign Up
|
Sign Up
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="four wide field">
|
<div class="field">
|
||||||
<div v-on:click="login()" class="ui fluid button">
|
<div v-on:click="login()" class="ui fluid button">
|
||||||
<i class="power icon"></i>
|
<i class="power icon"></i>
|
||||||
Login
|
Login
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="small-terms">
|
||||||
|
By signing up you agree to Solid Scribe's
|
||||||
|
<router-link to="/help">
|
||||||
|
Terms of Use
|
||||||
|
</router-link>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@ -83,7 +109,9 @@
|
|||||||
return {
|
return {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
username: '',
|
username: '',
|
||||||
password: ''
|
password: '',
|
||||||
|
authToken: '',
|
||||||
|
require2FA: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -139,14 +167,30 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
axios.post('/api/user/login', {'username': this.username, 'password': this.password})
|
axios.post('/api/user/login', {'username': this.username, 'password': this.password, 'authToken':this.authToken })
|
||||||
.then(({data}) => {
|
.then(({data}) => {
|
||||||
|
|
||||||
if(data == false){
|
//Enable 2FA on form
|
||||||
this.$bus.$emit('notification', 'Unable to Login - Incorrect Username or Password')
|
if(data.success == false && data.verificationRequired == true && this.require2FA == false){
|
||||||
|
this.$bus.$emit('notification', data.message)
|
||||||
|
this.require2FA = true
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.authForm.focus()
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.finalizeLogin(data)
|
if(data.success == false){
|
||||||
|
this.$bus.$emit('notification', data.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.success){
|
||||||
|
this.finalizeLogin(data)
|
||||||
|
return
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.$bus.$emit('notification', 'Unable to Login - Incorrect Username or Password')
|
this.$bus.$emit('notification', 'Unable to Login - Incorrect Username or Password')
|
||||||
@ -154,4 +198,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style type="text/css" scoped="true">
|
||||||
|
.small-terms {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: right;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
</style>
|
80
client/src/components/LogoComponent.vue
Normal file
80
client/src/components/LogoComponent.vue
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<template>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
id="svg8"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 132.29166 132.29167"
|
||||||
|
height="500"
|
||||||
|
width="500">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
style="display:inline"
|
||||||
|
transform="translate(0,-164.70832)"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
class="darken-accent"
|
||||||
|
id="path3813-4"
|
||||||
|
d="m 56.22733,165.36641 -55.56249926,15.875 8e-7,63.5 47.62499846,11.90625 v 27.78125 l -47.76066333,-13.9757 0.13566407,10.00695 55.56249926,15.875 v -47.625 l -47.6249985,-11.90625 -8e-7,-47.625 47.7606633,-13.94121 c 0.135664,-2.30629 -0.135664,-9.87129 -0.135664,-9.87129 z"
|
||||||
|
:style="`fill:${displayColor};fill-opacity:1;stroke:none;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1`" />
|
||||||
|
<path
|
||||||
|
class="brighten-accent"
|
||||||
|
id="path4563"
|
||||||
|
d="m 20.508581,220.92891 c 15.265814,-14.23899 27.809717,-7.68002 39.687499,3.96875 v -7.9375 C 51.75093,200.8366 37.512584,206.01499 20.508581,205.05391 Z"
|
||||||
|
:style="`fill:${displayColor};fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1`" />
|
||||||
|
<path
|
||||||
|
class="brighten-accent"
|
||||||
|
id="path4563-6"
|
||||||
|
d="m 111.78985,220.92891 c -15.265834,-14.23899 -27.809737,-7.68002 -39.68752,3.96875 v -7.9375 c 8.445151,-16.12356 22.683497,-10.94517 39.68752,-11.90625 z"
|
||||||
|
:style="`display:inline;fill:${displayColor};fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1`" />
|
||||||
|
<path
|
||||||
|
class="brighten-accent"
|
||||||
|
id="path3813-4-2"
|
||||||
|
d="m 76.07108,165.36641 55.5625,15.875 v 63.5 l -47.625,11.90625 v 27.78125 l 47.76067,-13.9757 -0.13567,10.00695 -55.5625,15.875 v -47.625 l 47.625,-11.90626 V 189.17891 L 75.93542,175.2377 c -0.13567,-2.30629 0.13566,-9.87129 0.13566,-9.87129 z"
|
||||||
|
:style="`display:inline;fill:${displayColor};fill-opacity:1;stroke:none;stroke-width:0.52916676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1`" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'LoadingIcon',
|
||||||
|
props:[ 'color' ],
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
displayColor: '#21BA45', //Default green color
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created(){
|
||||||
|
//Set color if passed
|
||||||
|
if(this.color){
|
||||||
|
this.displayColor = this.color
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style type="text/css" scoped>
|
||||||
|
.darken-accent {
|
||||||
|
filter: brightness(62%);
|
||||||
|
}
|
||||||
|
.brighten-accent {
|
||||||
|
filter: saturate(145%);
|
||||||
|
}
|
||||||
|
</style>
|
@ -2,9 +2,8 @@
|
|||||||
<!-- change class to .master-note-edit to have it popup on the screen -->
|
<!-- change class to .master-note-edit to have it popup on the screen -->
|
||||||
<div
|
<div
|
||||||
id="InputNotes"
|
id="InputNotes"
|
||||||
class="master-note-edit full-focus"
|
class="master-note-edit full-focus position-0"
|
||||||
@keyup.esc="close()"
|
@keyup.esc="closeButtonAction()"
|
||||||
:class="[ 'position-'+position ]"
|
|
||||||
>
|
>
|
||||||
|
|
||||||
<!-- Giant Edit Note Menu -->
|
<!-- Giant Edit Note Menu -->
|
||||||
@ -14,7 +13,7 @@
|
|||||||
<div class="edit-spacer"></div>
|
<div class="edit-spacer"></div>
|
||||||
|
|
||||||
<div class="menu-top-half">
|
<div class="menu-top-half">
|
||||||
<div class="edit-button" v-on:click="close()" data-tooltip="Close" data-position="bottom center" data-inverted>
|
<div class="edit-button" v-on:click="closeButtonAction()" data-tooltip="Close" data-position="bottom center" data-inverted>
|
||||||
<i class="close icon"></i>
|
<i class="close icon"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -61,7 +60,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="menu-bottom-half">
|
<div class="menu-bottom-half">
|
||||||
|
|
||||||
|
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/table`)" data-tooltip="Insert Table" data-position="bottom center" data-inverted>
|
||||||
|
<i class="border all icon"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="edit-button" v-on:click="insertDivide()" data-tooltip="Insert Divide" data-position="bottom center" data-inverted>
|
||||||
|
<i class="grip lines icon"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="removeFormatting()" data-tooltip="Remove Formatting" data-position="bottom center" data-inverted>
|
<div class="edit-button" v-on:click="removeFormatting()" data-tooltip="Remove Formatting" data-position="bottom center" data-inverted>
|
||||||
<i class="remove format icon"></i>
|
<i class="remove format icon"></i>
|
||||||
</div>
|
</div>
|
||||||
@ -95,7 +102,8 @@
|
|||||||
|
|
||||||
<div class="edit-divide"></div>
|
<div class="edit-divide"></div>
|
||||||
|
|
||||||
<!-- <div class="edit-button" v-on:click="onToggleArchived()" :data-tooltip="archived == 1?'Move to main list':'Move to Archive'" data-position="bottom center" data-inverted>
|
<!--
|
||||||
|
<div class="edit-button" v-on:click="onToggleArchived()" :data-tooltip="archived == 1?'Move to main list':'Move to Archive'" data-position="bottom center" data-inverted>
|
||||||
<span v-if="archived == 1"><i class="green archive icon"></i></span>
|
<span v-if="archived == 1"><i class="green archive icon"></i></span>
|
||||||
<span v-if="archived != 1"><i class="archive icon"></i></span>
|
<span v-if="archived != 1"><i class="archive icon"></i></span>
|
||||||
</div>
|
</div>
|
||||||
@ -105,17 +113,13 @@
|
|||||||
<span v-if="pinned != 1"><i class="pin icon"></i></span>
|
<span v-if="pinned != 1"><i class="pin icon"></i></span>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
|
||||||
<!-- data-tooltip="Files on note" -->
|
|
||||||
<!-- <div v-if="attachmentCount > 0" class="edit-button" v-on:click="openEditAttachment" data-tooltip="Files" data-position="bottom center" data-inverted>
|
|
||||||
<i class="folder icon"></i>
|
|
||||||
{{ attachmentCount }}
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<div class="edit-button" v-if="usersOnNote > 1">
|
<div class="edit-button" v-if="usersOnNote > 1">
|
||||||
<i class="green eye icon"></i> {{ usersOnNote }}
|
<i class="green eye icon"></i> {{ usersOnNote }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="edit-button" v-on:click="simulateTyping()">
|
<!--
|
||||||
|
<div class="edit-button" v-on:click="simulateTyping()">
|
||||||
<i class="purple bolt icon"></i>
|
<i class="purple bolt icon"></i>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
|
||||||
@ -132,7 +136,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bottom-edit-menu"></div>
|
<div class="bottom-edit-menu"></div>
|
||||||
@ -163,7 +166,7 @@
|
|||||||
</textarea>
|
</textarea>
|
||||||
|
|
||||||
<!-- Squire Box -->
|
<!-- Squire Box -->
|
||||||
<div id="squire-id" class="squire-box" ref="squirebox" placeholder="Note Text"></div>
|
<div id="squire-id" class="squire-box" ref="squirebox" placeholder="Type Note Here"></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -224,19 +227,19 @@
|
|||||||
<div class="sixteen wide column">
|
<div class="sixteen wide column">
|
||||||
<div class="ui labeled icon fluid basic button" v-on:click="sortList">
|
<div class="ui labeled icon fluid basic button" v-on:click="sortList">
|
||||||
<i class="sort amount up icon"></i>
|
<i class="sort amount up icon"></i>
|
||||||
Sort List items (Move checked to bottom)
|
Sort List
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="eight wide column">
|
<div class="eight wide column">
|
||||||
<div class="ui labeled icon fluid basic button" v-on:click="deleteCompletedListItems">
|
<div class="ui labeled icon fluid basic button" v-on:click="deleteCompletedListItems">
|
||||||
<i class="trash icon"></i>
|
<i class="trash icon"></i>
|
||||||
Delete Checked Items
|
Delete Checked
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="eight wide column">
|
<div class="eight wide column">
|
||||||
<div class="ui labeled icon fluid basic button" v-on:click="uncheckAllListItems">
|
<div class="ui labeled icon fluid basic button" v-on:click="uncheckAllListItems">
|
||||||
<i class="list ul icon"></i>
|
<i class="list ul icon"></i>
|
||||||
Uncheck all Checked items
|
Uncheck All
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="eight wide column">
|
<div class="eight wide column">
|
||||||
@ -245,6 +248,15 @@
|
|||||||
Simple Math
|
Simple Math
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="eight wide column">
|
||||||
|
<!-- data-tooltip="Files on note" -->
|
||||||
|
<div v-on:click="openEditAttachment" class="ui labeled icon fluid basic button">
|
||||||
|
<i class="folder icon"></i>
|
||||||
|
Note Files
|
||||||
|
{{ attachmentCount }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="sixteen wide column" v-if="rawTextId > 0">
|
<div class="sixteen wide column" v-if="rawTextId > 0">
|
||||||
<h2>Share Note</h2>
|
<h2>Share Note</h2>
|
||||||
<share-note-component
|
<share-note-component
|
||||||
@ -257,13 +269,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</side-slide-menu>
|
</side-slide-menu>
|
||||||
|
|
||||||
|
<!-- 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">
|
||||||
|
<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>
|
||||||
|
|
||||||
<!-- Show side shades if user is on desktop only -->
|
<!-- Show side shades if user is on desktop only -->
|
||||||
<div class="full-focus-shade shade1"
|
<div class="full-focus-shade shade1"
|
||||||
:class="{ 'slide-out-left':sizeDown }"
|
:class="{ 'slide-out-left':sizeDown }"
|
||||||
v-on:click="close()"></div>
|
v-on:click="closeButtonAction()"></div>
|
||||||
<div class="full-focus-shade shade2"
|
<div class="full-focus-shade shade2"
|
||||||
:class="{ 'slide-out-right':sizeDown }"
|
:class="{ 'slide-out-right':sizeDown }"
|
||||||
v-on:click="close()"></div>
|
v-on:click="closeButtonAction()"></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -335,6 +361,7 @@
|
|||||||
images: false,
|
images: false,
|
||||||
options: false,
|
options: false,
|
||||||
colorpicker: false,
|
colorpicker: false,
|
||||||
|
table: false,
|
||||||
|
|
||||||
//Diff text/sync text variables
|
//Diff text/sync text variables
|
||||||
diffTextTimeout: null,
|
diffTextTimeout: null,
|
||||||
@ -355,7 +382,7 @@
|
|||||||
//Handle changes in URL to
|
//Handle changes in URL to
|
||||||
|
|
||||||
if(newVal.id == undefined || newVal.id != this.noteid){
|
if(newVal.id == undefined || newVal.id != this.noteid){
|
||||||
this.close()
|
// this.closeButtonAction()
|
||||||
}
|
}
|
||||||
|
|
||||||
//Reset all note menus on URL change
|
//Reset all note menus on URL change
|
||||||
@ -364,6 +391,7 @@
|
|||||||
this.tags = false
|
this.tags = false
|
||||||
this.options = false
|
this.options = false
|
||||||
this.images = false
|
this.images = false
|
||||||
|
this.table = false
|
||||||
|
|
||||||
//If a menu value is set, open it
|
//If a menu value is set, open it
|
||||||
if(newVal.openMenu){
|
if(newVal.openMenu){
|
||||||
@ -394,18 +422,20 @@
|
|||||||
|
|
||||||
document.removeEventListener('visibilitychange', this.checkForUpdatedNote)
|
document.removeEventListener('visibilitychange', this.checkForUpdatedNote)
|
||||||
|
|
||||||
// if(this.editor){
|
//Obliterate squire instance
|
||||||
this.editor.destroy()
|
this.editor.destroy()
|
||||||
// }
|
|
||||||
|
|
||||||
|
this.close()
|
||||||
|
|
||||||
},
|
},
|
||||||
mounted: function() {
|
mounted: function() {
|
||||||
|
|
||||||
|
//Show loading for a minimum time
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
this.forceShowLoading = false
|
this.forceShowLoading = false
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|
||||||
document.addEventListener('visibilitychange', this.checkForUpdatedNote)
|
// document.addEventListener('visibilitychange', this.checkForUpdatedNote)
|
||||||
|
|
||||||
//Init squire as early as possible
|
//Init squire as early as possible
|
||||||
this.editor = new Squire( this.$refs.squirebox, {blockTag: 'p' })
|
this.editor = new Squire( this.$refs.squirebox, {blockTag: 'p' })
|
||||||
@ -599,6 +629,30 @@
|
|||||||
|
|
||||||
this.editor.addEventListener('keydown', event => {
|
this.editor.addEventListener('keydown', event => {
|
||||||
|
|
||||||
|
//Tab to increase quote level, tab + shigt to decrease quote level
|
||||||
|
const keyCode = event.key
|
||||||
|
if(keyCode == 'Tab'){
|
||||||
|
|
||||||
|
if(event.shiftKey){
|
||||||
|
this.editor.decreaseQuoteLevel()
|
||||||
|
} else {
|
||||||
|
this.editor.increaseQuoteLevel()
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
//Save on pressing CTRL/CMD + S
|
||||||
|
if(keyCode == 's' && (event.ctrlKey || event.metaKey) ){
|
||||||
|
|
||||||
|
this.$bus.$emit('notification', 'Note Saved')
|
||||||
|
this.save()
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
//Prevent new list items from having
|
//Prevent new list items from having
|
||||||
this.$nextTick( () => {
|
this.$nextTick( () => {
|
||||||
//Wait a moment to get item under cursor
|
//Wait a moment to get item under cursor
|
||||||
@ -612,10 +666,6 @@
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
this.editor.addEventListener('keydown', event => {
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
//Bind event handlers
|
//Bind event handlers
|
||||||
this.editor.addEventListener('keyup', event => {
|
this.editor.addEventListener('keyup', event => {
|
||||||
|
|
||||||
@ -682,7 +732,7 @@
|
|||||||
//Block notes you don't have access to from opening
|
//Block notes you don't have access to from opening
|
||||||
if(response.data === false){
|
if(response.data === false){
|
||||||
this.$bus.$emit('notification', 'Error opening Note')
|
this.$bus.$emit('notification', 'Error opening Note')
|
||||||
this.close(true)
|
this.close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -915,18 +965,21 @@
|
|||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
},
|
},
|
||||||
close(force = false){
|
closeButtonAction(){
|
||||||
|
this.sizeDown = true
|
||||||
|
//This timeout allows animation to play before closing
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$router.push('/notes')
|
||||||
|
}, 300)
|
||||||
|
},
|
||||||
|
close(){
|
||||||
|
|
||||||
// force = true
|
// force = true
|
||||||
|
|
||||||
// console.log(`Close Note ${this.noteid} -> force: ${force}, modified: ${this.modified}`)
|
// console.log(`Close Note ${this.noteid} -> force: ${force}, modified: ${this.modified}`)
|
||||||
|
|
||||||
if(force){
|
//Skip everything if foce close is true. Note will just die.
|
||||||
this.$bus.$emit('close_active_note', {
|
if(this.currentNoteId == 0){ return }
|
||||||
noteId: this.noteid, modified: this.modified
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loadingMessage = 'Saving...'
|
this.loadingMessage = 'Saving...'
|
||||||
this.loading = true
|
this.loading = true
|
||||||
@ -938,14 +991,10 @@
|
|||||||
axios.post('/api/note/reindex')
|
axios.post('/api/note/reindex')
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sizeDown = true
|
this.$bus.$emit('close_active_note', {
|
||||||
//This timeout allows animation to play before closing
|
noteId: this.noteid, modified: this.modified
|
||||||
setTimeout(() => {
|
})
|
||||||
this.$bus.$emit('close_active_note', {
|
return
|
||||||
noteId: this.noteid, modified: this.modified
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}, 300)
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
destroyWebSockets(){
|
destroyWebSockets(){
|
||||||
@ -1005,8 +1054,8 @@
|
|||||||
let element = this.$refs.titleTextarea
|
let element = this.$refs.titleTextarea
|
||||||
let padding = 0
|
let padding = 0
|
||||||
|
|
||||||
element.style.height = 'auto';
|
element.style.height = 'auto'
|
||||||
element.style.height = (element.scrollHeight + padding) +'px';
|
element.style.height = (element.scrollHeight + padding) +'px'
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1152,7 +1201,7 @@
|
|||||||
background-color: var(--menu-accent);
|
background-color: var(--menu-accent);
|
||||||
}
|
}
|
||||||
.edit-active {
|
.edit-active {
|
||||||
background-color: #21BA45;
|
background-color: var(--main-accent);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
.edit-divide {
|
.edit-divide {
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="time-ago-display" :class="{ 'hover-hide':(!$store.getters.getIsUserOnMobile) }">
|
<span class="time-ago-display" :class="{ 'hover-hide':(!$store.getters.getIsUserOnMobile) }">
|
||||||
{{$helpers.timeAgo(note.updated)}}
|
{{$helpers.timeAgo( note.updated )}}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="teeny-buttons" :class="{ 'hover-hide':(!$store.getters.getIsUserOnMobile) }">
|
<span class="teeny-buttons" :class="{ 'hover-hide':(!$store.getters.getIsUserOnMobile) }">
|
||||||
@ -234,12 +234,12 @@
|
|||||||
},
|
},
|
||||||
justClosed(){
|
justClosed(){
|
||||||
|
|
||||||
//Scroll note into view
|
// Scroll note into view
|
||||||
// this.$el.scrollIntoView({
|
this.$el.scrollIntoView({
|
||||||
// behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
// block: 'center',
|
block: 'center',
|
||||||
// inline: 'center'
|
inline: 'center'
|
||||||
// })
|
})
|
||||||
|
|
||||||
//After scroll, trigger green outline animation
|
//After scroll, trigger green outline animation
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -356,13 +356,14 @@
|
|||||||
|
|
||||||
/*Strict font sizes for card display*/
|
/*Strict font sizes for card display*/
|
||||||
.small-text {
|
.small-text {
|
||||||
max-height: 261px;
|
max-height: 267px;
|
||||||
|
width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
.small-text, .small-text > p, .small-text > h1, .small-text > h2 {
|
.small-text, .small-text > p, .small-text > h1, .small-text > h2 {
|
||||||
/*font-size: 1.0em !important;*/
|
/*font-size: 1.0em !important;*/
|
||||||
font-size: 16px !important;
|
font-size: 14px !important;
|
||||||
}
|
}
|
||||||
.small-text > p, , .small-text > h1, .small-text > h2 {
|
.small-text > p, , .small-text > h1, .small-text > h2 {
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
@ -370,7 +371,7 @@
|
|||||||
.big-text > p:first-child,
|
.big-text > p:first-child,
|
||||||
.big-text > h1, .big-text > h2 {
|
.big-text > h1, .big-text > h2 {
|
||||||
/*font-size: 1.3em !important;*/
|
/*font-size: 1.3em !important;*/
|
||||||
font-size: 17px !important;
|
font-size: 20px !important;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
@ -415,14 +416,14 @@
|
|||||||
border-color: var(--border_color);
|
border-color: var(--border_color);
|
||||||
/*width: calc(33.333% - 10px);*/
|
/*width: calc(33.333% - 10px);*/
|
||||||
width: calc(25% - 10px);
|
width: calc(25% - 10px);
|
||||||
min-width: 190px;
|
/*min-width: 190px;*/
|
||||||
min-height: 130px;
|
min-height: 130px;
|
||||||
/*transition: box-shadow 0.3s;*/
|
/*transition: box-shadow 0.3s;*/
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
line-height: 1.8rem;
|
line-height: 1.8rem;
|
||||||
letter-spacing: 0.02rem;
|
letter-spacing: 0.05rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@ -555,27 +556,50 @@
|
|||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tweak mobile display to show only one column */
|
/* Break points determine when display cards shrink */
|
||||||
@media only screen and (min-width: 1500px) {
|
@media only screen and (max-width: 700px) {
|
||||||
.note-title-display-card {
|
|
||||||
width: calc(20% - 10px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media only screen and (max-width: 740px) {
|
|
||||||
.note-title-display-card {
|
.note-title-display-card {
|
||||||
width: calc(100% + 10px);
|
width: calc(100% + 10px);
|
||||||
margin: 0px -5px 10px -5px;
|
margin: 0px -5px 10px -5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@media only screen and (min-width: 700px) and (max-width: 900px) {
|
||||||
|
.note-title-display-card {
|
||||||
|
width: calc(50% - 10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (min-width: 900px) and (max-width: 1100px) {
|
||||||
|
.note-title-display-card {
|
||||||
|
width: calc(33.33333% - 10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (min-width: 1100px) and (max-width: 1300px) {
|
||||||
|
.note-title-display-card {
|
||||||
|
width: calc(25% - 10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (min-width: 1300px) and (max-width: 1800px) {
|
||||||
|
.note-title-display-card {
|
||||||
|
width: calc(20% - 10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (min-width: 1800px) {
|
||||||
|
.note-title-display-card {
|
||||||
|
width: calc(16.66666% - 10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*Animations for cool border effects*/
|
/*Animations for cool border effects*/
|
||||||
@keyframes bgin {
|
@keyframes bgin {
|
||||||
0% {
|
0% {
|
||||||
background-image:
|
background-image:
|
||||||
linear-gradient(to right, #21BA45 50%, #21BA45 100%), /* TopLeft to Right */
|
linear-gradient(to right, var(--main-accent) 50%, var(--main-accent) 100%), /* TopLeft to Right */
|
||||||
linear-gradient(to bottom, #21BA45 50%, #21BA45 100%), /* TopRight to Bottom */
|
linear-gradient(to bottom, var(--main-accent) 50%, var(--main-accent) 100%), /* TopRight to Bottom */
|
||||||
linear-gradient(to right, #21BA45 50%, #21BA45 100%), /* BottomLeft to Right*/
|
linear-gradient(to right, var(--main-accent) 50%, var(--main-accent) 100%), /* BottomLeft to Right*/
|
||||||
linear-gradient(to bottom, #21BA45 50%, #21BA45 100%); /* TopLeft to Bottom */
|
linear-gradient(to bottom, var(--main-accent) 50%, var(--main-accent) 100%); /* TopLeft to Bottom */
|
||||||
/*Initial state, no BG*/
|
/*Initial state, no BG*/
|
||||||
background-size: 0 4px, 4px 0, 0 4px, 4px 0;
|
background-size: 0 4px, 4px 0, 0 4px, 4px 0;
|
||||||
}
|
}
|
||||||
@ -590,10 +614,10 @@
|
|||||||
30% {
|
30% {
|
||||||
background-size: 100% 4px, 4px 100%, 100% 4px, 4px 100%;
|
background-size: 100% 4px, 4px 100%, 100% 4px, 4px 100%;
|
||||||
background-image:
|
background-image:
|
||||||
linear-gradient(to right, #21BA45 50%, #21BA45 100%), /* TopLeft to Right */
|
linear-gradient(to right, var(--main-accent) 50%, var(--main-accent) 100%), /* TopLeft to Right */
|
||||||
linear-gradient(to bottom, #21BA45 50%, #21BA45 100%), /* TopRight to Bottom */
|
linear-gradient(to bottom, var(--main-accent) 50%, var(--main-accent) 100%), /* TopRight to Bottom */
|
||||||
linear-gradient(to right, #21BA45 50%, #21BA45 100%), /* BottomLeft to Right*/
|
linear-gradient(to right, var(--main-accent) 50%, var(--main-accent) 100%), /* BottomLeft to Right*/
|
||||||
linear-gradient(to bottom, #21BA45 50%, #21BA45 100%); /* TopLeft to Bottom */
|
linear-gradient(to bottom, var(--main-accent) 50%, var(--main-accent) 100%); /* TopLeft to Bottom */
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
background-image:
|
background-image:
|
||||||
|
@ -98,13 +98,17 @@
|
|||||||
},
|
},
|
||||||
beforeCreate: function(){
|
beforeCreate: function(){
|
||||||
},
|
},
|
||||||
mounted: function(){
|
beforeMount(){
|
||||||
|
|
||||||
//search clear
|
//search clear
|
||||||
this.$bus.$on('reset_fast_filters', () => {
|
this.$bus.$on('reset_fast_filters', () => {
|
||||||
this.searchTerm = ''
|
this.searchTerm = ''
|
||||||
this.tagSuggestions = []
|
this.tagSuggestions = []
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
beforeDestroy(){
|
||||||
|
this.$bus.$off('reset_fast_filters')
|
||||||
|
},
|
||||||
|
mounted: function(){
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -148,7 +152,6 @@
|
|||||||
|
|
||||||
if(response.data && response.data.id){
|
if(response.data && response.data.id){
|
||||||
this.$router.push('/notes/open/'+response.data.id)
|
this.$router.push('/notes/open/'+response.data.id)
|
||||||
this.$bus.$emit('open_note', response.data.id)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => { this.$bus.$emit('notification', 'Failed to create note') })
|
.catch(error => { this.$bus.$emit('notification', 'Failed to create note') })
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li>Shared notes can be read and edited by you and all shared users.</li>
|
<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>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>
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,6 +17,7 @@ const SquireButtonFunctions = {
|
|||||||
//
|
//
|
||||||
|
|
||||||
pathChangeEvent(e){
|
pathChangeEvent(e){
|
||||||
|
|
||||||
//Reset all button states
|
//Reset all button states
|
||||||
this.activeBold = false
|
this.activeBold = false
|
||||||
this.activeTitle = false
|
this.activeTitle = false
|
||||||
@ -143,28 +144,23 @@ const SquireButtonFunctions = {
|
|||||||
// Uncheck All List Items
|
// Uncheck All List Items
|
||||||
//
|
//
|
||||||
|
|
||||||
//Close menu if user is on mobile, then sort list
|
|
||||||
if(this.$store.getters.getIsUserOnMobile){
|
|
||||||
this.options = false
|
|
||||||
}
|
|
||||||
|
|
||||||
//Fetch the container
|
//Fetch the container
|
||||||
let container = document.getElementById('squire-id')
|
let container = document.getElementById('squire-id')
|
||||||
|
|
||||||
Array.from( container.getElementsByClassName('active') ).forEach(item => {
|
Array.from( container.getElementsByClassName('active') ).forEach(item => {
|
||||||
item.classList.remove('active');
|
item.classList.remove('active');
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//Close menu if user is on mobile, then sort list
|
||||||
|
if(this.$store.getters.getIsUserOnMobile){
|
||||||
|
this.$router.go(-1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
deleteCompletedListItems(){
|
deleteCompletedListItems(){
|
||||||
//
|
//
|
||||||
// Delete Completed List Items
|
// Delete Completed List Items
|
||||||
//
|
//
|
||||||
|
|
||||||
//Close menu if user is on mobile, then sort list
|
|
||||||
if(this.$store.getters.getIsUserOnMobile){
|
|
||||||
this.options = false
|
|
||||||
}
|
|
||||||
|
|
||||||
//Fetch the container
|
//Fetch the container
|
||||||
let container = document.getElementById('squire-id')
|
let container = document.getElementById('squire-id')
|
||||||
|
|
||||||
@ -210,17 +206,17 @@ const SquireButtonFunctions = {
|
|||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//Close menu if user is on mobile, then sort list
|
||||||
|
if(this.$store.getters.getIsUserOnMobile){
|
||||||
|
this.$router.go(-1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
sortList(){
|
sortList(){
|
||||||
//
|
//
|
||||||
// Sort list, checked at the bottom, unchecked at the top
|
// Sort list, checked at the bottom, unchecked at the top
|
||||||
//
|
//
|
||||||
|
|
||||||
//Close menu if user is on mobile, then sort list
|
|
||||||
if(this.$store.getters.getIsUserOnMobile){
|
|
||||||
this.options = false
|
|
||||||
}
|
|
||||||
|
|
||||||
//Fetch the container
|
//Fetch the container
|
||||||
let container = document.getElementById('squire-id')
|
let container = document.getElementById('squire-id')
|
||||||
|
|
||||||
@ -274,17 +270,17 @@ const SquireButtonFunctions = {
|
|||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//Close menu if user is on mobile
|
||||||
|
if(this.$store.getters.getIsUserOnMobile){
|
||||||
|
this.$router.go(-1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
calculateMath(){
|
calculateMath(){
|
||||||
//
|
//
|
||||||
// Find math in note and calculate the outcome
|
// Find math in note and calculate the outcome
|
||||||
//
|
//
|
||||||
|
|
||||||
//Close menu if user is on mobile, then sort list
|
|
||||||
if(this.$store.getters.getIsUserOnMobile){
|
|
||||||
this.options = false
|
|
||||||
}
|
|
||||||
|
|
||||||
//Fetch the container
|
//Fetch the container
|
||||||
let container = document.getElementById('squire-id')
|
let container = document.getElementById('squire-id')
|
||||||
|
|
||||||
@ -327,6 +323,11 @@ const SquireButtonFunctions = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//Close menu if user is on mobile, then sort list
|
||||||
|
if(this.$store.getters.getIsUserOnMobile){
|
||||||
|
this.$router.go(-1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setText(inText){
|
setText(inText){
|
||||||
|
|
||||||
@ -338,6 +339,33 @@ const SquireButtonFunctions = {
|
|||||||
|
|
||||||
return this.editor.getHTML()
|
return this.editor.getHTML()
|
||||||
},
|
},
|
||||||
|
insertDivide(){
|
||||||
|
|
||||||
|
this.editor.insertHTML(`<p><div class='divide'></div><br></p>`)
|
||||||
|
this.editor.focus()
|
||||||
|
this.editor.moveCursorToEnd()
|
||||||
|
},
|
||||||
|
insertTable(tall, wide){
|
||||||
|
console.log(`Table: ${wide} x ${tall}`)
|
||||||
|
|
||||||
|
//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 += '</table></div><p><br></p>'
|
||||||
|
|
||||||
|
this.editor.insertHTML(tableSyntax)
|
||||||
|
this.editor.focus()
|
||||||
|
this.editor.moveCursorToEnd()
|
||||||
|
|
||||||
|
this.$router.go(-1)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -110,7 +110,7 @@
|
|||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<h3 class="subtext">
|
<h3 class="subtext">
|
||||||
A free, secure Note App<i class="i cursor icon blinking"></i>
|
A free, secure, online note taking application<i class="i cursor icon blinking"></i>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -210,18 +210,7 @@
|
|||||||
<i class="bottom left corner blue pen icon"></i>
|
<i class="bottom left corner blue pen icon"></i>
|
||||||
</i>
|
</i>
|
||||||
Document Editing Tools
|
Document Editing Tools
|
||||||
<div class="sub header">Bold, Underline, Title, Add Links, Add Tables Color Text, Color Background and more.</div>
|
<div class="sub header">Bold, Underline, Title, Add Links, Add Tables, Color Text, Color Background and more.</div>
|
||||||
</div>
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<h2 class="ui dividing header">
|
|
||||||
<div class="content">
|
|
||||||
<i class="icons">
|
|
||||||
<i class="grey tags icon"></i>
|
|
||||||
<i class="bottom left corner purple plus icon"></i>
|
|
||||||
</i>
|
|
||||||
Tag Notes
|
|
||||||
<div class="sub header">Easily add and edit tags on notes then sort notes by tag.</div>
|
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
@ -236,6 +225,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
|
<h2 class="ui dividing header">
|
||||||
|
<div class="content">
|
||||||
|
<i class="icons">
|
||||||
|
<i class="grey tags icon"></i>
|
||||||
|
<i class="bottom left corner purple plus icon"></i>
|
||||||
|
</i>
|
||||||
|
Tag Notes
|
||||||
|
<div class="sub header">Easily add and edit tags on notes then sort notes by tag.</div>
|
||||||
|
</div>
|
||||||
|
</h2>
|
||||||
|
|
||||||
<h2 class="ui dividing header">
|
<h2 class="ui dividing header">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<i class="icons">
|
<i class="icons">
|
||||||
@ -254,7 +254,7 @@
|
|||||||
<i class="bottom left corner share icon"></i>
|
<i class="bottom left corner share icon"></i>
|
||||||
</i>
|
</i>
|
||||||
Share Encrypted Notes
|
Share Encrypted Notes
|
||||||
<div class="sub header">Share notes with friends without compromising security. And its easy to disable sharing.</div>
|
<div class="sub header">Share encrypted notes with friends without compromising security.</div>
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
@ -290,6 +290,17 @@
|
|||||||
<div class="sub header">Add text to Images and links than can be searched.</div>
|
<div class="sub header">Add text to Images and links than can be searched.</div>
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
|
<h2 class="ui dividing header">
|
||||||
|
<div class="content">
|
||||||
|
<i class="icons">
|
||||||
|
<i class="grey tv icon"></i>
|
||||||
|
<i class="bottom left corner blue mobile icon"></i>
|
||||||
|
</i>
|
||||||
|
Two Factor Authentication
|
||||||
|
<div class="sub header">Enable two factor authentication for added peace of mind.</div>
|
||||||
|
</div>
|
||||||
|
</h2>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="four wide column">
|
<div class="four wide column">
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>You will remain logged in on this browser, for 30 days or until you log out.</p>
|
<p>You will remain logged in on this browser, for 20 days or until you log out.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
<i v-if="titleView" class="th icon"></i>
|
<i v-if="titleView" class="th icon"></i>
|
||||||
<i v-if="!titleView" class="bars icon"></i>
|
<i v-if="!titleView" class="bars icon"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="eight wide column" v-if="showClear">
|
<div class="eight wide column" v-if="showClear">
|
||||||
@ -117,7 +117,7 @@
|
|||||||
:onClick="openNote"
|
:onClick="openNote"
|
||||||
:data="note"
|
:data="note"
|
||||||
:title-view="titleView"
|
:title-view="titleView"
|
||||||
:currently-open="(activeNoteId1 == note.id || activeNoteId2 == note.id)"
|
:currently-open="activeNoteId1 == note.id"
|
||||||
:key="note.id + note.color + '-' +note.title.length + '-' +note.subtext.length + '-' + note.tag_count + note.updated"
|
:key="note.id + note.color + '-' +note.title.length + '-' +note.subtext.length + '-' + note.tag_count + note.updated"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -132,13 +132,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<input-notes
|
<note-input-panel
|
||||||
v-if="activeNoteId1 != null"
|
v-if="activeNoteId1 != null"
|
||||||
:key="'active_note_'+activeNoteId1"
|
:key="activeNoteId1"
|
||||||
:noteid="activeNoteId1"
|
:noteid="activeNoteId1"
|
||||||
:position="activeNote1Position"
|
|
||||||
:url-data="$route.params"
|
:url-data="$route.params"
|
||||||
ref="note1" />
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -151,7 +150,7 @@
|
|||||||
name: 'SearchBar',
|
name: 'SearchBar',
|
||||||
components: {
|
components: {
|
||||||
|
|
||||||
'input-notes': () => import(/* webpackChunkName: "NoteInputPanel" */ '@/components/NoteInputPanel.vue'),
|
'note-input-panel': () => import(/* webpackChunkName: "NoteInputPanel" */ '@/components/NoteInputPanel.vue'),
|
||||||
|
|
||||||
'note-title-display-card': require('@/components/NoteTitleDisplayCard.vue').default,
|
'note-title-display-card': require('@/components/NoteTitleDisplayCard.vue').default,
|
||||||
// 'fast-filters': require('@/components/FastFilters.vue').default,
|
// 'fast-filters': require('@/components/FastFilters.vue').default,
|
||||||
@ -247,7 +246,7 @@
|
|||||||
|
|
||||||
//Do not update note if its open
|
//Do not update note if its open
|
||||||
if(this.activeNoteId1 != noteId){
|
if(this.activeNoteId1 != noteId){
|
||||||
this.updateSingleNote(noteId, false)
|
this.updateSingleNote(noteId, true)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -264,10 +263,18 @@
|
|||||||
//Close note event
|
//Close note event
|
||||||
this.$bus.$on('close_active_note', ({noteId, modified}) => {
|
this.$bus.$on('close_active_note', ({noteId, modified}) => {
|
||||||
|
|
||||||
this.closeNote()
|
if(modified){
|
||||||
|
console.log('Just closed Note -> ' + noteId + ', modified -> ', modified)
|
||||||
|
}
|
||||||
|
|
||||||
|
//A note has been closed
|
||||||
|
if(this.$route.fullPath != '/notes'){
|
||||||
|
this.$router.push('/notes')
|
||||||
|
}
|
||||||
|
|
||||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||||
//Focus and animate if modified
|
//Focus and animate if modified
|
||||||
this.updateSingleNote(parseInt(noteId), modified)
|
this.updateSingleNote(noteId, modified)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.$bus.$on('note_deleted', (noteId) => {
|
this.$bus.$on('note_deleted', (noteId) => {
|
||||||
@ -312,35 +319,25 @@
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
//New note button pushes open note event
|
//Reload page content - don't trigger if load is in progress
|
||||||
this.$bus.$on('open_note', noteId => {
|
|
||||||
this.openNote(noteId)
|
|
||||||
})
|
|
||||||
|
|
||||||
//Reload page content
|
|
||||||
this.$bus.$on('note_reload', () => {
|
this.$bus.$on('note_reload', () => {
|
||||||
this.reset()
|
if(!this.loadingInProgress){
|
||||||
|
this.reset()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
//Mount notes on load if note ID is set
|
|
||||||
if(this.$route.params && this.$route.params.id){
|
|
||||||
const id = this.$route.params.id
|
|
||||||
this.openNote(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('scroll', this.onScroll)
|
window.addEventListener('scroll', this.onScroll)
|
||||||
|
|
||||||
//Close notes when back button is pressed
|
//Close notes when back button is pressed
|
||||||
window.addEventListener('hashchange', this.hashChangeAction)
|
// window.addEventListener('hashchange', this.hashChangeAction)
|
||||||
|
|
||||||
//update note on visibility change
|
//update note on visibility change
|
||||||
document.addEventListener('visibilitychange', this.visibiltyChangeAction);
|
// document.addEventListener('visibilitychange', this.visibiltyChangeAction);
|
||||||
|
|
||||||
},
|
},
|
||||||
beforeDestroy(){
|
beforeDestroy(){
|
||||||
window.removeEventListener('scroll', this.onScroll)
|
window.removeEventListener('scroll', this.onScroll)
|
||||||
window.removeEventListener('hashchange', this.hashChangeAction)
|
// document.removeEventListener('visibilitychange', this.visibiltyChangeAction)
|
||||||
document.removeEventListener('visibilitychange', this.visibiltyChangeAction)
|
|
||||||
|
|
||||||
this.$bus.$off('note_reload')
|
this.$bus.$off('note_reload')
|
||||||
this.$bus.$off('close_active_note')
|
this.$bus.$off('close_active_note')
|
||||||
@ -348,7 +345,6 @@
|
|||||||
this.$bus.$off('note_deleted')
|
this.$bus.$off('note_deleted')
|
||||||
this.$bus.$off('update_fast_filters')
|
this.$bus.$off('update_fast_filters')
|
||||||
this.$bus.$off('update_search_term')
|
this.$bus.$off('update_search_term')
|
||||||
this.$bus.$off('open_note')
|
|
||||||
|
|
||||||
//We want to remove event listeners, but something here is messing them up and preventing ALL event listeners from working
|
//We want to remove event listeners, but something here is messing them up and preventing ALL event listeners from working
|
||||||
// this.$off() // Remove all event listeners
|
// this.$off() // Remove all event listeners
|
||||||
@ -356,11 +352,20 @@
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
||||||
|
//Open note on load if ID is set
|
||||||
|
if(this.$route.params.id > 1){
|
||||||
|
this.activeNoteId1 = this.$route.params.id
|
||||||
|
}
|
||||||
|
|
||||||
//Loads initial batch and tags
|
//Loads initial batch and tags
|
||||||
this.reset()
|
this.reset()
|
||||||
|
|
||||||
// this.search(true, this.firstLoadBatchSize, false)
|
},
|
||||||
// .then( r => this.search(false, this.batchSize, true))
|
watch: {
|
||||||
|
'$route.params.id': function(id){
|
||||||
|
//Open note on ID, null id will close note
|
||||||
|
this.activeNoteId1 = id
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleTitleView(){
|
toggleTitleView(){
|
||||||
@ -382,17 +387,9 @@
|
|||||||
if(nodeClick == 'A'){ return }
|
if(nodeClick == 'A'){ return }
|
||||||
}
|
}
|
||||||
|
|
||||||
//1 note open
|
//Open note if a link was not clicked
|
||||||
if(this.activeNoteId1 == null){
|
this.$router.push('/notes/open/'+id)
|
||||||
this.activeNoteId1 = id
|
return
|
||||||
this.activeNote1Position = 0 //Middel of page
|
|
||||||
this.$router.push('/notes/open/'+this.activeNoteId1).catch(e => { console.log(e) })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
},
|
|
||||||
closeNote(position){
|
|
||||||
this.activeNoteId1 = null
|
|
||||||
this.$router.push('/notes')
|
|
||||||
},
|
},
|
||||||
toggleTagFilter(tagId){
|
toggleTagFilter(tagId){
|
||||||
|
|
||||||
@ -429,34 +426,6 @@
|
|||||||
|
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
//Try to close notes on URL hash change /notes/open/123 to /notes - parse 123, close note id 123
|
|
||||||
hashChangeAction(event){
|
|
||||||
|
|
||||||
//Clean up path of hash change
|
|
||||||
let path = window.location.protocol + '//' + window.location.hostname + window.location.pathname + window.location.hash
|
|
||||||
let newPath = event.newURL.replace(path,'')
|
|
||||||
let oldPath = event.oldURL.replace(path,'')
|
|
||||||
|
|
||||||
// console.log(this.$route.params)
|
|
||||||
// console.log(this.$router)
|
|
||||||
|
|
||||||
//Open note if user goes forward to a note id
|
|
||||||
if(this.$route.params && this.$route.params.id){
|
|
||||||
this.openNote(this.$route.params.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
//If we go from open note ID to no note ID, close the note
|
|
||||||
if(newPath == '' && oldPath.indexOf('/open/') != -1){
|
|
||||||
//Pull note ID out of URL
|
|
||||||
const noteIdToClose = oldPath.split('/').pop()
|
|
||||||
|
|
||||||
// console.log(noteIdToClose)
|
|
||||||
|
|
||||||
if(this.$refs.note1 && this.$refs.note1.currentNoteId == noteIdToClose){
|
|
||||||
// this.$refs.note1.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
visibiltyChangeAction(event){
|
visibiltyChangeAction(event){
|
||||||
|
|
||||||
//Fuck this shit, just use web sockets
|
//Fuck this shit, just use web sockets
|
||||||
@ -484,8 +453,11 @@
|
|||||||
let note = null
|
let note = null
|
||||||
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0] && this.$refs['note-'+noteId][0].note){
|
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0] && this.$refs['note-'+noteId][0].note){
|
||||||
note = this.$refs['note-'+noteId][0].note
|
note = this.$refs['note-'+noteId][0].note
|
||||||
|
//Show that note is working on updating
|
||||||
|
this.$refs['note-'+noteId][0].showWorking = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Lookup one note using passed in ID
|
//Lookup one note using passed in ID
|
||||||
const postData = {
|
const postData = {
|
||||||
searchQuery: this.searchTerm,
|
searchQuery: this.searchTerm,
|
||||||
@ -508,18 +480,13 @@
|
|||||||
|
|
||||||
if(note && newNote){
|
if(note && newNote){
|
||||||
|
|
||||||
//Don't move notes that were not changed
|
|
||||||
if(note.updated == newNote.updated){
|
|
||||||
// return
|
|
||||||
}
|
|
||||||
|
|
||||||
//go through each prop and update it with new values
|
//go through each prop and update it with new values
|
||||||
Object.keys(newNote).forEach(prop => {
|
Object.keys(newNote).forEach(prop => {
|
||||||
note[prop] = newNote[prop]
|
note[prop] = newNote[prop]
|
||||||
})
|
})
|
||||||
|
|
||||||
//Push new note to front if its modified
|
//Push new note to front if its modified or we want it to
|
||||||
if(focuseAndAnimate){
|
if( focuseAndAnimate || note.updated != newNote.updated ){
|
||||||
|
|
||||||
// Find note, in section, move to front
|
// Find note, in section, move to front
|
||||||
Object.keys(this.noteSections).forEach( key => {
|
Object.keys(this.noteSections).forEach( key => {
|
||||||
@ -536,6 +503,7 @@
|
|||||||
this.$nextTick( () => {
|
this.$nextTick( () => {
|
||||||
//Trigger close animation on note
|
//Trigger close animation on note
|
||||||
this.$refs['note-'+noteId][0].justClosed()
|
this.$refs['note-'+noteId][0].justClosed()
|
||||||
|
this.$refs['note-'+noteId][0].showWorking = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,9 +515,14 @@
|
|||||||
//Trigger close animation on note
|
//Trigger close animation on note
|
||||||
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0]){
|
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0]){
|
||||||
this.$refs['note-'+noteId][0].justClosed()
|
this.$refs['note-'+noteId][0].justClosed()
|
||||||
|
this.$refs['note-'+noteId][0].showWorking = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0]){
|
||||||
|
this.$refs['note-'+noteId][0].showWorking = false
|
||||||
|
}
|
||||||
|
|
||||||
//Trigger section rebuild
|
//Trigger section rebuild
|
||||||
this.rebuildNoteCategorise()
|
this.rebuildNoteCategorise()
|
||||||
})
|
})
|
||||||
@ -610,7 +583,6 @@
|
|||||||
|
|
||||||
//Perform search - or die
|
//Perform search - or die
|
||||||
this.loadingInProgress = true
|
this.loadingInProgress = true
|
||||||
// console.time('Fetch TitleCard Batch '+notesInNextLoad)
|
|
||||||
axios.post('/api/note/search', postData)
|
axios.post('/api/note/search', postData)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
|
||||||
@ -735,7 +707,6 @@
|
|||||||
this.fastFilters = {}
|
this.fastFilters = {}
|
||||||
this.foundAttachments = [] //Remove all attachments
|
this.foundAttachments = [] //Remove all attachments
|
||||||
|
|
||||||
this.$bus.$emit('reset_fast_filters')
|
|
||||||
this.updateFastFilters(5) //This loads notes
|
this.updateFastFilters(5) //This loads notes
|
||||||
|
|
||||||
},
|
},
|
||||||
|
@ -14,6 +14,11 @@
|
|||||||
|
|
||||||
<div class="sixteen wide middle aligned column" v-if="quickNoteId > 0">
|
<div class="sixteen wide middle aligned column" v-if="quickNoteId > 0">
|
||||||
|
|
||||||
|
<div v-if="quickNoteId" v-on:click="openNoteEdit" class="ui compact basic button">
|
||||||
|
<i class="file outline icon"></i>
|
||||||
|
Open Note
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="ui compact basic right floated button shrinking" v-if="!showNewNoteConfirm" v-on:click="showNewNoteConfirm = true">
|
<div class="ui compact basic right floated button shrinking" v-if="!showNewNoteConfirm" v-on:click="showNewNoteConfirm = true">
|
||||||
<i class="sync alternate reload icon"></i>
|
<i class="sync alternate reload icon"></i>
|
||||||
New Scratch Pad
|
New Scratch Pad
|
||||||
@ -46,10 +51,6 @@
|
|||||||
<i class="folder open outline icon"></i>
|
<i class="folder open outline icon"></i>
|
||||||
Files
|
Files
|
||||||
</div>
|
</div>
|
||||||
<div v-if="quickNoteId" v-on:click="openNoteEdit" class="ui right floated basic button">
|
|
||||||
<i class="file outline icon"></i>
|
|
||||||
Open Note
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
257
client/src/pages/SettingsPage.vue
Normal file
257
client/src/pages/SettingsPage.vue
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
<template>
|
||||||
|
<div class="ui grid">
|
||||||
|
<div class="row"></div>
|
||||||
|
<!-- spacer column -->
|
||||||
|
<div class="sixteen wide column">
|
||||||
|
<h2 class="ui dividing header">
|
||||||
|
<i class="cog icon"></i>
|
||||||
|
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">
|
||||||
|
<div class="sixteen wide column">
|
||||||
|
<h3 class="ui header">
|
||||||
|
Accent Color
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
v-for="color in themeColors"
|
||||||
|
class="ui compact basic button"
|
||||||
|
:style="`background: linear-gradient(0deg, ${color} 4%, rgba(0,0,0,0) 5%);`"
|
||||||
|
v-on:click="setAccentColor(color)">
|
||||||
|
<logo style="width: 33px; height: auto;" :color="color" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Enable Two Factor -->
|
||||||
|
<div class="ui segment">
|
||||||
|
<h3>Two Factor Authentication</h3>
|
||||||
|
<div class="ui stackable grid">
|
||||||
|
<div class="four wide column">
|
||||||
|
<p>1. Enter Password and get QR</p>
|
||||||
|
<div class="ui fluid action input">
|
||||||
|
<input type="password" placeholder="Current Password" v-model="password">
|
||||||
|
|
||||||
|
<div v-if="password.length == 0" class="ui disabled button">
|
||||||
|
Get QR code
|
||||||
|
</div>
|
||||||
|
<div v-if="password.length > 0" class="ui green button" v-on:click="getQrCode()">
|
||||||
|
Get QR code
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="five wide column">
|
||||||
|
<p>2. Scan QR Code</p>
|
||||||
|
<p v-if="qrCode == ''">QR Code Will appear here.</p>
|
||||||
|
<img v-if="qrCode != ''" :src="qrCode" alt="QR Code">
|
||||||
|
</div>
|
||||||
|
<div class="four wide column">
|
||||||
|
<p>3. Verify with code</p>
|
||||||
|
<div class="ui input" v-if="qrCode != ''">
|
||||||
|
<input type="text" placeholder="Verification Code" v-model="verificationToken" v-on:keyup.enter="verifyQrCode()">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- change password -->
|
||||||
|
<div class="ui segment">
|
||||||
|
<h3>Change Password</h3>
|
||||||
|
<div class="ui grid">
|
||||||
|
<div class="five wide column">
|
||||||
|
<label>Current Password</label>
|
||||||
|
<div class="ui fluid input">
|
||||||
|
<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 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 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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- log out -->
|
||||||
|
<div class="ui segment">
|
||||||
|
<div class="ui grid">
|
||||||
|
<div class="sixteen wide column">
|
||||||
|
<h3>Log Out</h3>
|
||||||
|
</div>
|
||||||
|
<div class="eight wide column">
|
||||||
|
<div class="ui button" v-on:click="logout()">
|
||||||
|
Log Out this browser
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="eight wide column">
|
||||||
|
<div class="ui button" v-on:click="revokeAllSessions()">
|
||||||
|
Log Out all other browsers
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SettingsPage',
|
||||||
|
components: {
|
||||||
|
'logo':require('@/components/LogoComponent.vue').default,
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
password: '',
|
||||||
|
qrCode: '',
|
||||||
|
verificationToken: '',
|
||||||
|
showNewNoteConfirm: false,
|
||||||
|
|
||||||
|
themeColors: [
|
||||||
|
'#21BA45', //Green
|
||||||
|
'#b5cc18', //Lime
|
||||||
|
'#00b5ad', //Teal
|
||||||
|
'#2185d0', //Blue
|
||||||
|
'#7128b9', //Violet
|
||||||
|
'#a333c8', // "Purple"
|
||||||
|
'#e03997', //Pink
|
||||||
|
'#db2828', //Red
|
||||||
|
'#f2711c', //Orange
|
||||||
|
'#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('/')
|
||||||
|
axios.post('/api/user/logout')
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$bus.$emit('notification', 'Logged Out')
|
||||||
|
}, 200)
|
||||||
|
},
|
||||||
|
setAccentColor(color){
|
||||||
|
|
||||||
|
let root = document.documentElement
|
||||||
|
root.style.setProperty('--main-accent', color)
|
||||||
|
localStorage.setItem('main-accent', color)
|
||||||
|
|
||||||
|
if(!color || color == '#21BA45'){
|
||||||
|
localStorage.removeItem('main-accent')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getQrCode(){
|
||||||
|
|
||||||
|
axios.post('/api/user/twofactorsetup', { password:this.password })
|
||||||
|
.then(({data}) => {
|
||||||
|
this.qrCode = data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
verifyQrCode(){
|
||||||
|
|
||||||
|
axios.post('/api/user/verifytwofactorsetuptoken', { password:this.password, token: this.verificationToken })
|
||||||
|
.then(({data}) => {
|
||||||
|
if(data == true){
|
||||||
|
//Two FA is set up
|
||||||
|
} else {
|
||||||
|
//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.')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -4,38 +4,55 @@
|
|||||||
<div class="sixteen wide column"></div>
|
<div class="sixteen wide column"></div>
|
||||||
|
|
||||||
<div class="sixteen wide column" v-if="text.length > 0 || title.length > 0">
|
<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>
|
</div>
|
||||||
|
|
||||||
<div class="sixteen wide column" v-if="!$store.getters.getLoggedIn">
|
<div class="sixteen wide column" v-if="!$store.getters.getLoggedIn">
|
||||||
<div class="ui text container">
|
<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="ui segment">
|
||||||
<div class="content">
|
|
||||||
Solid Scribe is an easy, free, secure Note App
|
<div class="ui grid">
|
||||||
<div class="sub header">
|
<div class="three wide middle aligned center aligned column">
|
||||||
Encrypted notes, only readable by you. Unless you share them.
|
<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>
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -99,7 +116,7 @@
|
|||||||
|
|
||||||
<style type="text/css" scoped>
|
<style type="text/css" scoped>
|
||||||
.small-logo {
|
.small-logo {
|
||||||
width: 30px;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -6,6 +6,7 @@ import Router from 'vue-router'
|
|||||||
const HomePage = () => import(/* webpackChunkName: "HomePage" */ '@/pages/HomePage')
|
const HomePage = () => import(/* webpackChunkName: "HomePage" */ '@/pages/HomePage')
|
||||||
const LoginPage = () => import(/* webpackChunkName: "LoginPage" */ '@/pages/LoginPage')
|
const LoginPage = () => import(/* webpackChunkName: "LoginPage" */ '@/pages/LoginPage')
|
||||||
const HelpPage = () => import(/* webpackChunkName: "HelpPage" */ '@/pages/HelpPage')
|
const HelpPage = () => import(/* webpackChunkName: "HelpPage" */ '@/pages/HelpPage')
|
||||||
|
const SettingsPage = () => import(/* webpackChunkName: "SettingsPage" */ '@/pages/SettingsPage')
|
||||||
const SharePage = () => import(/* webpackChunkName: "SharePage" */ '@/pages/SharePage')
|
const SharePage = () => import(/* webpackChunkName: "SharePage" */ '@/pages/SharePage')
|
||||||
const NotesPage = () => import(/* webpackChunkName: "NotesPage" */ '@/pages/NotesPage')
|
const NotesPage = () => import(/* webpackChunkName: "NotesPage" */ '@/pages/NotesPage')
|
||||||
const QuickPage = () => import(/* webpackChunkName: "QuickPage" */ '@/pages/QuickPage')
|
const QuickPage = () => import(/* webpackChunkName: "QuickPage" */ '@/pages/QuickPage')
|
||||||
@ -51,6 +52,12 @@ export default new Router({
|
|||||||
name: 'Help',
|
name: 'Help',
|
||||||
meta: {title:'Help'},
|
meta: {title:'Help'},
|
||||||
component: HelpPage
|
component: HelpPage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/settings',
|
||||||
|
name: 'Settings',
|
||||||
|
meta: {title:'Settings'},
|
||||||
|
component: SettingsPage
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/public/note/:id/:token',
|
path: '/public/note/:id/:token',
|
||||||
|
@ -85,6 +85,7 @@ export default new Vuex.Store({
|
|||||||
Object.keys( themes[currentTheme] ).forEach( attribute => {
|
Object.keys( themes[currentTheme] ).forEach( attribute => {
|
||||||
root.style.setProperty('--'+attribute, themes[currentTheme][attribute])
|
root.style.setProperty('--'+attribute, themes[currentTheme][attribute])
|
||||||
})
|
})
|
||||||
|
|
||||||
},
|
},
|
||||||
detectIsUserOnMobile(state){
|
detectIsUserOnMobile(state){
|
||||||
|
|
||||||
|
265
package-lock.json
generated
265
package-lock.json
generated
@ -49,6 +49,19 @@
|
|||||||
"uri-js": "^4.2.2"
|
"uri-js": "^4.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
|
||||||
|
},
|
||||||
|
"ansi-styles": {
|
||||||
|
"version": "3.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||||
|
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||||
|
"requires": {
|
||||||
|
"color-convert": "^1.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"append-field": {
|
"append-field": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
|
||||||
@ -112,11 +125,21 @@
|
|||||||
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
|
||||||
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
|
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
|
||||||
},
|
},
|
||||||
|
"base32.js": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/base32.js/-/base32.js-0.0.1.tgz",
|
||||||
|
"integrity": "sha1-0EVzalex9sE58MffQlGKhOkbsro="
|
||||||
|
},
|
||||||
"base64-arraybuffer": {
|
"base64-arraybuffer": {
|
||||||
"version": "0.1.5",
|
"version": "0.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
|
||||||
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
|
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
|
||||||
},
|
},
|
||||||
|
"base64-js": {
|
||||||
|
"version": "1.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
|
||||||
|
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
|
||||||
|
},
|
||||||
"base64id": {
|
"base64id": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
|
||||||
@ -182,11 +205,39 @@
|
|||||||
"resolved": "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz",
|
||||||
"integrity": "sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA=="
|
"integrity": "sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA=="
|
||||||
},
|
},
|
||||||
|
"buffer": {
|
||||||
|
"version": "5.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz",
|
||||||
|
"integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==",
|
||||||
|
"requires": {
|
||||||
|
"base64-js": "^1.0.2",
|
||||||
|
"ieee754": "^1.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"buffer-alloc": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
|
||||||
|
"requires": {
|
||||||
|
"buffer-alloc-unsafe": "^1.1.0",
|
||||||
|
"buffer-fill": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"buffer-alloc-unsafe": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="
|
||||||
|
},
|
||||||
"buffer-equal-constant-time": {
|
"buffer-equal-constant-time": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||||
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
|
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
|
||||||
},
|
},
|
||||||
|
"buffer-fill": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw="
|
||||||
|
},
|
||||||
"buffer-from": {
|
"buffer-from": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||||
@ -229,6 +280,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
|
||||||
"integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
|
"integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
|
||||||
},
|
},
|
||||||
|
"camelcase": {
|
||||||
|
"version": "5.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||||
|
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
|
||||||
|
},
|
||||||
"camelize": {
|
"camelize": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz",
|
||||||
@ -252,6 +308,29 @@
|
|||||||
"parse5": "^3.0.1"
|
"parse5": "^3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"cliui": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
|
||||||
|
"requires": {
|
||||||
|
"string-width": "^3.1.0",
|
||||||
|
"strip-ansi": "^5.2.0",
|
||||||
|
"wrap-ansi": "^5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color-convert": {
|
||||||
|
"version": "1.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
|
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||||
|
"requires": {
|
||||||
|
"color-name": "1.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color-name": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||||
|
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||||
|
},
|
||||||
"combined-stream": {
|
"combined-stream": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
@ -394,6 +473,11 @@
|
|||||||
"ms": "2.0.0"
|
"ms": "2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"decamelize": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||||
|
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
|
||||||
|
},
|
||||||
"delayed-stream": {
|
"delayed-stream": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
@ -441,6 +525,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dijkstrajs": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-082BIh4+pAdCz83lVtTpnpjdxxs="
|
||||||
|
},
|
||||||
"dns-prefetch-control": {
|
"dns-prefetch-control": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz",
|
||||||
@ -509,6 +598,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
|
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
|
||||||
},
|
},
|
||||||
|
"emoji-regex": {
|
||||||
|
"version": "7.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
|
||||||
|
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
|
||||||
|
},
|
||||||
"encodeurl": {
|
"encodeurl": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||||
@ -708,6 +802,14 @@
|
|||||||
"unpipe": "~1.0.0"
|
"unpipe": "~1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"find-up": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
|
||||||
|
"requires": {
|
||||||
|
"locate-path": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"forever-agent": {
|
"forever-agent": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||||
@ -746,6 +848,11 @@
|
|||||||
"is-property": "^1.0.2"
|
"is-property": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"get-caller-file": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
|
||||||
|
},
|
||||||
"getpass": {
|
"getpass": {
|
||||||
"version": "0.1.7",
|
"version": "0.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
|
||||||
@ -926,6 +1033,11 @@
|
|||||||
"safer-buffer": ">= 2.1.2 < 3"
|
"safer-buffer": ">= 2.1.2 < 3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ieee754": {
|
||||||
|
"version": "1.1.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
|
||||||
|
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
|
||||||
|
},
|
||||||
"indexof": {
|
"indexof": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
|
||||||
@ -941,6 +1053,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
|
||||||
"integrity": "sha1-N9905DCg5HVQ/lSi3v4w2KzZX2U="
|
"integrity": "sha1-N9905DCg5HVQ/lSi3v4w2KzZX2U="
|
||||||
},
|
},
|
||||||
|
"is-fullwidth-code-point": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
|
||||||
|
},
|
||||||
"is-property": {
|
"is-property": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
|
||||||
@ -1040,6 +1157,15 @@
|
|||||||
"safe-buffer": "^5.0.1"
|
"safe-buffer": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"locate-path": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
|
||||||
|
"requires": {
|
||||||
|
"p-locate": "^3.0.0",
|
||||||
|
"path-exists": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.15",
|
"version": "4.17.15",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||||
@ -1257,6 +1383,27 @@
|
|||||||
"ee-first": "1.1.1"
|
"ee-first": "1.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"p-limit": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||||
|
"requires": {
|
||||||
|
"p-try": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p-locate": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
|
||||||
|
"requires": {
|
||||||
|
"p-limit": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p-try": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
|
||||||
|
},
|
||||||
"parse5": {
|
"parse5": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
|
||||||
@ -1286,6 +1433,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||||
"integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ="
|
"integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ="
|
||||||
},
|
},
|
||||||
|
"path-exists": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
|
||||||
|
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
|
||||||
|
},
|
||||||
"path-to-regexp": {
|
"path-to-regexp": {
|
||||||
"version": "0.1.7",
|
"version": "0.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||||
@ -1296,6 +1448,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
||||||
},
|
},
|
||||||
|
"pngjs": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w=="
|
||||||
|
},
|
||||||
"process-nextick-args": {
|
"process-nextick-args": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
@ -1325,6 +1482,27 @@
|
|||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||||
"integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew="
|
"integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew="
|
||||||
},
|
},
|
||||||
|
"qrcode": {
|
||||||
|
"version": "1.4.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.4.4.tgz",
|
||||||
|
"integrity": "sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q==",
|
||||||
|
"requires": {
|
||||||
|
"buffer": "^5.4.3",
|
||||||
|
"buffer-alloc": "^1.2.0",
|
||||||
|
"buffer-from": "^1.1.1",
|
||||||
|
"dijkstrajs": "^1.0.1",
|
||||||
|
"isarray": "^2.0.1",
|
||||||
|
"pngjs": "^3.3.0",
|
||||||
|
"yargs": "^13.2.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"isarray": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"qs": {
|
"qs": {
|
||||||
"version": "6.5.2",
|
"version": "6.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||||
@ -1407,6 +1585,16 @@
|
|||||||
"lodash": "^4.17.15"
|
"lodash": "^4.17.15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"require-directory": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||||
|
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
|
||||||
|
},
|
||||||
|
"require-main-filename": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
|
||||||
|
},
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
@ -1465,6 +1653,11 @@
|
|||||||
"send": "0.17.1"
|
"send": "0.17.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"set-blocking": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
|
||||||
|
},
|
||||||
"setprototypeof": {
|
"setprototypeof": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
|
||||||
@ -1599,6 +1792,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"speakeasy": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/speakeasy/-/speakeasy-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-hckaBxsJpcuGQlkNmDVmFl9XYTo=",
|
||||||
|
"requires": {
|
||||||
|
"base32.js": "0.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"sqlstring": {
|
"sqlstring": {
|
||||||
"version": "2.3.2",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz",
|
||||||
@ -1635,6 +1836,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
|
||||||
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
|
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
|
||||||
},
|
},
|
||||||
|
"string-width": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
|
||||||
|
"requires": {
|
||||||
|
"emoji-regex": "^7.0.1",
|
||||||
|
"is-fullwidth-code-point": "^2.0.0",
|
||||||
|
"strip-ansi": "^5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"string_decoder": {
|
"string_decoder": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz",
|
||||||
@ -1643,6 +1854,14 @@
|
|||||||
"safe-buffer": "~5.1.0"
|
"safe-buffer": "~5.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"strip-ansi": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "^4.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"to-array": {
|
"to-array": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
|
||||||
@ -1755,6 +1974,21 @@
|
|||||||
"isexe": "^2.0.0"
|
"isexe": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"which-module": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
|
||||||
|
},
|
||||||
|
"wrap-ansi": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^3.2.0",
|
||||||
|
"string-width": "^3.0.0",
|
||||||
|
"strip-ansi": "^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ws": {
|
"ws": {
|
||||||
"version": "7.2.1",
|
"version": "7.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-7.2.1.tgz",
|
||||||
@ -1775,11 +2009,42 @@
|
|||||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||||
"integrity": "sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q="
|
"integrity": "sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q="
|
||||||
},
|
},
|
||||||
|
"y18n": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
|
||||||
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
|
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
|
||||||
},
|
},
|
||||||
|
"yargs": {
|
||||||
|
"version": "13.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
|
||||||
|
"integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
|
||||||
|
"requires": {
|
||||||
|
"cliui": "^5.0.0",
|
||||||
|
"find-up": "^3.0.0",
|
||||||
|
"get-caller-file": "^2.0.1",
|
||||||
|
"require-directory": "^2.1.1",
|
||||||
|
"require-main-filename": "^2.0.0",
|
||||||
|
"set-blocking": "^2.0.0",
|
||||||
|
"string-width": "^3.0.0",
|
||||||
|
"which-module": "^2.0.0",
|
||||||
|
"y18n": "^4.0.0",
|
||||||
|
"yargs-parser": "^13.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"yargs-parser": {
|
||||||
|
"version": "13.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
|
||||||
|
"integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
|
||||||
|
"requires": {
|
||||||
|
"camelcase": "^5.0.0",
|
||||||
|
"decamelize": "^1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"yeast": {
|
"yeast": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
|
||||||
|
@ -21,9 +21,11 @@
|
|||||||
"multer": "^1.4.2",
|
"multer": "^1.4.2",
|
||||||
"mysql2": "^1.7.0",
|
"mysql2": "^1.7.0",
|
||||||
"node-tesseract-ocr": "^1.0.0",
|
"node-tesseract-ocr": "^1.0.0",
|
||||||
|
"qrcode": "^1.4.4",
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
"request-promise": "^4.2.5",
|
"request-promise": "^4.2.5",
|
||||||
"socket.io": "^2.3.0"
|
"socket.io": "^2.3.0",
|
||||||
|
"speakeasy": "^2.0.0"
|
||||||
},
|
},
|
||||||
"_moduleAliases": {
|
"_moduleAliases": {
|
||||||
"@root": ".",
|
"@root": ".",
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
const db = require('@config/database')
|
const db = require('@config/database')
|
||||||
const jwt = require('jsonwebtoken')
|
const jwt = require('jsonwebtoken')
|
||||||
const cs = require('@helpers/CryptoString')
|
const cs = require('@helpers/CryptoString')
|
||||||
|
const speakeasy = require('speakeasy')
|
||||||
|
|
||||||
let Auth = {}
|
let Auth = {}
|
||||||
|
|
||||||
const tokenSecretKey = process.env.JSON_KEY
|
const tokenSecretKey = process.env.JSON_KEY
|
||||||
|
|
||||||
|
//Creates session token
|
||||||
Auth.createToken = (userId, masterKey, pastId = null, pastCreatedDate = null) => {
|
Auth.createToken = (userId, masterKey, pastId = null, pastCreatedDate = null) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
@ -41,6 +43,7 @@ Auth.createToken = (userId, masterKey, pastId = null, pastCreatedDate = null) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Decodes session token
|
||||||
Auth.decodeToken = (token, request = null) => {
|
Auth.decodeToken = (token, request = null) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
@ -120,6 +123,7 @@ Auth.decodeToken = (token, request = null) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Auth.terminateSession = (sessionId) => {
|
Auth.terminateSession = (sessionId) => {
|
||||||
|
|
||||||
return db.promise().query('DELETE from user_active_session WHERE session_id = ?', [sessionId])
|
return db.promise().query('DELETE from user_active_session WHERE session_id = ?', [sessionId])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +134,143 @@ Auth.deletAllLoginKeys = (userId) => {
|
|||||||
return db.promise().query('DELETE FROM user_active_session WHERE user_hash = ?', [userHash])
|
return db.promise().query('DELETE FROM user_active_session WHERE user_hash = ?', [userHash])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Generate two factor secret key, if key is not verified, return a new one
|
||||||
|
//Only return QR code if user is not verified, only show unique QR code, once
|
||||||
|
Auth.generateTwoFactorSecretKey = (userId, password) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
const QRCode = require('qrcode')
|
||||||
|
|
||||||
|
const User = require('@models/User')
|
||||||
|
User.getMasterKey(userId, password)
|
||||||
|
.then(masterKey => {
|
||||||
|
return db.promise().query('SELECT username, two_fa_enabled FROM user WHERE id = ?', [userId])
|
||||||
|
})
|
||||||
|
.then((r,f) => {
|
||||||
|
|
||||||
|
const tfaEnabled = r[0][0]['two_fa_enabled'] == 1
|
||||||
|
const username = r[0][0]['username']
|
||||||
|
|
||||||
|
if(!tfaEnabled){
|
||||||
|
|
||||||
|
var secret = speakeasy.generateSecret({length: 20, name: username+' - solidscribe.com'})
|
||||||
|
const twoFaSecretToken = secret.base32
|
||||||
|
const otpauthUrl = secret.otpauth_url
|
||||||
|
|
||||||
|
//Generate test Token
|
||||||
|
var token = speakeasy.totp({
|
||||||
|
secret: twoFaSecretToken,
|
||||||
|
encoding: 'base32'
|
||||||
|
})
|
||||||
|
|
||||||
|
db.promise().query('UPDATE user SET two_fa_secret = ? WHERE id = ? LIMIT 1', [twoFaSecretToken, userId])
|
||||||
|
.then((r,f) => {
|
||||||
|
|
||||||
|
QRCode.toDataURL(otpauthUrl, function(err, qrCode) {
|
||||||
|
|
||||||
|
//Return A QR code for the user, one time use
|
||||||
|
return resolve({qrCode, token})
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return reject('Two factor already enabled for user')
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log('Key auth error')
|
||||||
|
console.log(error)
|
||||||
|
return reject(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth.setTwoFactorEnabled = (userId, password, token, enable) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
Auth.validateTwoFactorToken(userId, password, token)
|
||||||
|
.then(isValid => {
|
||||||
|
if(isValid){
|
||||||
|
db.promise().query('UPDATE user SET two_fa_enabled = ? WHERE id = ? LIMIT 1', [enable, userId])
|
||||||
|
.then((r, f) => {
|
||||||
|
return resolve(true)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return resolve(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth.validateTwoFactorToken = (userId, password, token) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
const User = require('@models/User')
|
||||||
|
User.getMasterKey(userId, password)
|
||||||
|
.then(masterKey => {
|
||||||
|
return db.promise().query('SELECT two_fa_secret FROM user WHERE id = ?', [userId])
|
||||||
|
})
|
||||||
|
.then((r,f) => {
|
||||||
|
|
||||||
|
//Verify Token
|
||||||
|
const tokenValidates = speakeasy.totp.verify({
|
||||||
|
'secret': r[0][0]['two_fa_secret'],
|
||||||
|
'encoding': 'base32',
|
||||||
|
'token': token,
|
||||||
|
'window': 6
|
||||||
|
})
|
||||||
|
|
||||||
|
return resolve(tokenValidates)
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log('Token Validation Error')
|
||||||
|
return resolve(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth.testTwoFactor = () => {
|
||||||
|
|
||||||
|
const userId = 93
|
||||||
|
const pass = '1'
|
||||||
|
|
||||||
|
|
||||||
|
let tfaToken = null
|
||||||
|
console.log('Test Two Factor')
|
||||||
|
|
||||||
|
Auth.generateTwoFactorSecretKey(userId, pass)
|
||||||
|
.then( ({qrCode, token}) => {
|
||||||
|
|
||||||
|
tfaToken = token
|
||||||
|
|
||||||
|
Auth.validateTwoFactorToken(userId, pass, tfaToken)
|
||||||
|
.then(validToken => {
|
||||||
|
console.log('Is Token Valid:', validToken)
|
||||||
|
})
|
||||||
|
|
||||||
|
return Auth.setTwoFactorEnabled(userId, pass, tfaToken, true)
|
||||||
|
})
|
||||||
|
.then(twoFactorEnbled => {
|
||||||
|
console.log('Was it enabled?', twoFactorEnbled)
|
||||||
|
|
||||||
|
return Auth.setTwoFactorEnabled(userId, pass, tfaToken, false)
|
||||||
|
|
||||||
|
})
|
||||||
|
.then(twoFactorEnbled => {
|
||||||
|
console.log('Was it disabled?', twoFactorEnbled)
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
Auth.test = () => {
|
Auth.test = () => {
|
||||||
|
|
||||||
const testUserId = 22
|
const testUserId = 22
|
||||||
|
@ -259,13 +259,15 @@ const printResults = true
|
|||||||
let UserTest = require('@models/User')
|
let UserTest = require('@models/User')
|
||||||
let NoteTest = require('@models/Note')
|
let NoteTest = require('@models/Note')
|
||||||
let AuthTest = require('@helpers/Auth')
|
let AuthTest = require('@helpers/Auth')
|
||||||
|
|
||||||
|
Auth.testTwoFactor()
|
||||||
|
|
||||||
Auth.test()
|
Auth.test()
|
||||||
UserTest.keyPairTest('genMan15', '1', printResults)
|
UserTest.keyPairTest('genMan23', '1', printResults)
|
||||||
.then( ({testUserId, masterKey}) => NoteTest.test(testUserId, masterKey, printResults))
|
.then( ({testUserId, masterKey}) => NoteTest.test(testUserId, masterKey, printResults))
|
||||||
.then( message => {
|
.then( message => {
|
||||||
if(printResults) console.log(message)
|
if(printResults) console.log(message)
|
||||||
})
|
})
|
||||||
// Test Area
|
|
||||||
|
|
||||||
|
|
||||||
//Test
|
//Test
|
||||||
|
@ -182,7 +182,7 @@ Note.create = (userId, noteTitle = '', noteText = '', masterKey) => {
|
|||||||
const encryptedText = cs.encrypt(masterKey, salt, textObject)
|
const encryptedText = cs.encrypt(masterKey, salt, textObject)
|
||||||
|
|
||||||
db.promise()
|
db.promise()
|
||||||
.query(`INSERT INTO note_raw_text (text, salt, updated) VALUE (?, ?, ?)`, [encryptedText, salt, created])
|
.query(`INSERT INTO note_raw_text (text, salt, updated) VALUE (?, ?, ?)`, [encryptedText, salt, (+new Date)])
|
||||||
.then( (rows, fields) => {
|
.then( (rows, fields) => {
|
||||||
|
|
||||||
const rawTextId = rows[0].insertId
|
const rawTextId = rows[0].insertId
|
||||||
@ -515,7 +515,7 @@ Note.setPinned = (userId, noteId, pinnedBoolean) => {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
const pinned = pinnedBoolean ? 1:0
|
const pinned = pinnedBoolean ? 1:0
|
||||||
const now = Math.round((+new Date)/1000)
|
const now = (+new Date)
|
||||||
|
|
||||||
//Update other note attributes
|
//Update other note attributes
|
||||||
return db.promise()
|
return db.promise()
|
||||||
@ -532,7 +532,7 @@ Note.setArchived = (userId, noteId, archivedBoolead) => {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
const archived = archivedBoolead ? 1:0
|
const archived = archivedBoolead ? 1:0
|
||||||
const now = Math.round((+new Date)/1000)
|
const now = (+new Date)
|
||||||
|
|
||||||
//Update other note attributes
|
//Update other note attributes
|
||||||
return db.promise()
|
return db.promise()
|
||||||
@ -549,7 +549,7 @@ Note.setTrashed = (userId, noteId, trashedBoolean, masterKey) => {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
const trashed = trashedBoolean ? 1:0
|
const trashed = trashedBoolean ? 1:0
|
||||||
const now = Math.round((+new Date)/1000)
|
const now = (+new Date)
|
||||||
|
|
||||||
//Update other note attributes
|
//Update other note attributes
|
||||||
return db.promise()
|
return db.promise()
|
||||||
@ -1048,7 +1048,7 @@ Note.search = (userId, searchQuery, searchTags, fastFilters, masterKey) => {
|
|||||||
// Always prioritize pinned notes in searches.
|
// Always prioritize pinned notes in searches.
|
||||||
|
|
||||||
//Default Sort, order by last updated
|
//Default Sort, order by last updated
|
||||||
let defaultOrderBy = ' ORDER BY note.pinned DESC, updated DESC, note.created DESC, note.opened DESC, id DESC'
|
let defaultOrderBy = ' ORDER BY note.pinned DESC, updated DESC, note.created DESC, note.opened DESC'
|
||||||
|
|
||||||
//Order by Last Created Date
|
//Order by Last Created Date
|
||||||
if(fastFilters.lastCreated == 1){
|
if(fastFilters.lastCreated == 1){
|
||||||
|
@ -10,19 +10,28 @@ QuickNote.get = (userId, masterKey) => {
|
|||||||
|
|
||||||
db.promise()
|
db.promise()
|
||||||
.query(`
|
.query(`
|
||||||
SELECT note.id FROM note WHERE quick_note = 1 AND user_id = ? LIMIT 1
|
SELECT note.id FROM note WHERE quick_note = 1 AND user_id = ? LIMIT 1`, [userId])
|
||||||
`, [userId])
|
|
||||||
.then((rows, fields) => {
|
.then((rows, fields) => {
|
||||||
|
|
||||||
//Quick Note is set, return note text
|
//Quick Note is set, return note text
|
||||||
if(rows[0][0] != undefined){
|
if(rows[0][0] != undefined){
|
||||||
|
|
||||||
let noteId = rows[0][0].id
|
let noteId = rows[0][0].id
|
||||||
Note.get(userId, noteId, masterKey)
|
return resolve({'noteId':noteId})
|
||||||
.then( noteObject => {
|
|
||||||
return resolve(noteObject)
|
|
||||||
})
|
|
||||||
} else {
|
} 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})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,22 +5,32 @@ const Note = require('@models/Note')
|
|||||||
const db = require('@config/database')
|
const db = require('@config/database')
|
||||||
const Auth = require('@helpers/Auth')
|
const Auth = require('@helpers/Auth')
|
||||||
const cs = require('@helpers/CryptoString')
|
const cs = require('@helpers/CryptoString')
|
||||||
|
const speakeasy = require('speakeasy')
|
||||||
|
|
||||||
let User = module.exports = {}
|
let User = module.exports = {}
|
||||||
|
|
||||||
const version = '3.0.1'
|
const version = '3.1.5'
|
||||||
|
|
||||||
//Login a user, if that user does not exist create them
|
//Login a user, if that user does not exist create them
|
||||||
//Issues login token
|
//Issues login token
|
||||||
User.login = (username, password) => {
|
User.login = (username, password, authToken = null) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
const lowerName = username.toLowerCase();
|
const lowerName = username.toLowerCase()
|
||||||
|
|
||||||
|
let statusObject = {
|
||||||
|
success: false,
|
||||||
|
token: null,
|
||||||
|
userId: null,
|
||||||
|
verificationRequired: false,
|
||||||
|
message: 'Incorrect Username or Password'
|
||||||
|
}
|
||||||
|
|
||||||
db.promise()
|
db.promise()
|
||||||
.query('SELECT * FROM user WHERE username = ? LIMIT 1', [lowerName])
|
.query('SELECT * FROM user WHERE username = ? LIMIT 1', [lowerName])
|
||||||
.then((rows, fields) => {
|
.then((rows, fields) => {
|
||||||
|
|
||||||
|
//
|
||||||
// Login User
|
// Login User
|
||||||
//
|
//
|
||||||
if(rows[0].length == 1){
|
if(rows[0].length == 1){
|
||||||
@ -28,34 +38,76 @@ User.login = (username, password) => {
|
|||||||
//Pull out user data from database results
|
//Pull out user data from database results
|
||||||
const lookedUpUser = rows[0][0]
|
const lookedUpUser = rows[0][0]
|
||||||
|
|
||||||
//hash the password and check for a match
|
//Verify Token if set
|
||||||
// const salt = new Buffer(lookedUpUser.salt, 'binary')
|
const tokenValidates = speakeasy.totp.verify({
|
||||||
const salt = Buffer.from(lookedUpUser.salt, 'binary')
|
'secret': lookedUpUser['two_fa_secret'],
|
||||||
crypto.pbkdf2(password, salt, lookedUpUser.iterations, 512, 'sha512', function(err, delivered_key){
|
'encoding': 'base32',
|
||||||
if(delivered_key.toString('hex') === lookedUpUser.password){
|
'token': authToken,
|
||||||
|
'window': 2
|
||||||
|
})
|
||||||
|
|
||||||
User.generateMasterKey(lookedUpUser.id, password)
|
if(lookedUpUser.two_fa_enabled == 1 && !authToken){
|
||||||
.then( result => User.getMasterKey(lookedUpUser.id, password))
|
|
||||||
.then(masterKey => {
|
|
||||||
|
|
||||||
User.generateKeypair(lookedUpUser.id, masterKey)
|
statusObject['verificationRequired'] = true
|
||||||
.then(({publicKey, privateKey}) => {
|
statusObject['message'] = '2FA authentication required.'
|
||||||
|
|
||||||
//Passback a json web token
|
return resolve(statusObject)
|
||||||
Auth.createToken(lookedUpUser.id, masterKey)
|
}
|
||||||
.then(token => {
|
|
||||||
return resolve({ token: token, userId:lookedUpUser.id })
|
if(lookedUpUser.two_fa_enabled == 1 && !tokenValidates){
|
||||||
|
|
||||||
|
statusObject['verificationRequired'] = true
|
||||||
|
statusObject['message'] = 'Invalid Authorization Token.'
|
||||||
|
|
||||||
|
return resolve(statusObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lookedUpUser.two_fa_enabled == 0 || (lookedUpUser.two_fa_enabled == 1 && tokenValidates) ){
|
||||||
|
|
||||||
|
//hash the password and check for a match
|
||||||
|
|
||||||
|
const salt = Buffer.from(lookedUpUser.salt, 'binary')
|
||||||
|
crypto.pbkdf2(password, salt, lookedUpUser.iterations, 512, 'sha512', function(err, delivered_key){
|
||||||
|
if(delivered_key.toString('hex') === lookedUpUser.password){
|
||||||
|
|
||||||
|
User.generateMasterKey(lookedUpUser.id, password)
|
||||||
|
.then( result => User.getMasterKey(lookedUpUser.id, password))
|
||||||
|
.then(masterKey => {
|
||||||
|
|
||||||
|
User.generateKeypair(lookedUpUser.id, masterKey)
|
||||||
|
.then(({publicKey, privateKey}) => {
|
||||||
|
|
||||||
|
//Passback a json web token
|
||||||
|
Auth.createToken(lookedUpUser.id, masterKey)
|
||||||
|
.then(token => {
|
||||||
|
|
||||||
|
statusObject['token'] = token
|
||||||
|
statusObject['userId'] = lookedUpUser.id
|
||||||
|
statusObject['success'] = true
|
||||||
|
|
||||||
|
return resolve(statusObject)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
return resolve(statusObject)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
reject('Password does not match database')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
return reject('Incorrect Username or Password')
|
|
||||||
|
//If user is not found, say two factor authentication is required
|
||||||
|
statusObject['verificationRequired'] = true
|
||||||
|
statusObject['message'] = '2FA authentication required.'
|
||||||
|
|
||||||
|
//Show fake auth token message
|
||||||
|
if(authToken){
|
||||||
|
statusObject['message'] = 'Invalid Authorization Token.'
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(statusObject)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
@ -186,6 +238,12 @@ User.getCounts = (userId) => {
|
|||||||
|
|
||||||
Object.assign(countTotals, rows[0][0]) //combine results
|
Object.assign(countTotals, rows[0][0]) //combine results
|
||||||
|
|
||||||
|
return db.promise().query('SELECT id AS quickNote FROM note WHERE quick_note = 1 AND user_id = ?', [userId])
|
||||||
|
|
||||||
|
}).then( (rows, fields) => {
|
||||||
|
|
||||||
|
Object.assign(countTotals, rows[0][0]) //combine results
|
||||||
|
|
||||||
//Convert everything to an int or 0
|
//Convert everything to an int or 0
|
||||||
Object.keys(countTotals).forEach( key => {
|
Object.keys(countTotals).forEach( key => {
|
||||||
const count = parseInt(countTotals[key])
|
const count = parseInt(countTotals[key])
|
||||||
@ -253,13 +311,12 @@ User.generateMasterKey = (userId, password) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
User.getMasterKey = (userId, password) => {
|
User.getMasterKey = (userId, password) => {
|
||||||
|
|
||||||
if(!userId || !password){
|
|
||||||
reject('Need userId and password to fetch key')
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
if(!userId || !password){
|
||||||
|
reject('Need userId and password to fetch key')
|
||||||
|
}
|
||||||
|
|
||||||
db.promise().query('SELECT * FROM user_key WHERE user_id = ? LIMIT 1', [userId])
|
db.promise().query('SELECT * FROM user_key WHERE user_id = ? LIMIT 1', [userId])
|
||||||
.then((rows, fields) => {
|
.then((rows, fields) => {
|
||||||
|
|
||||||
@ -375,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) => {
|
User.deleteUser = (userId, password) => {
|
||||||
|
|
||||||
//Verify user is correct by decryptig master key with password
|
//Verify user is correct by decryptig master key with password
|
||||||
@ -414,6 +531,7 @@ User.keyPairTest = (testUserName = 'genMan', password = '1', printResults) => {
|
|||||||
|
|
||||||
const randomUsername = Math.random().toString(36).substring(2, 15);
|
const randomUsername = Math.random().toString(36).substring(2, 15);
|
||||||
const randomPassword = '1'
|
const randomPassword = '1'
|
||||||
|
const secondPassword = '2'
|
||||||
|
|
||||||
User.register(testUserName, password)
|
User.register(testUserName, password)
|
||||||
.then( ({ token, userId }) => {
|
.then( ({ token, userId }) => {
|
||||||
@ -421,7 +539,7 @@ User.keyPairTest = (testUserName = 'genMan', password = '1', printResults) => {
|
|||||||
|
|
||||||
if(printResults) console.log('Test: Register User '+testUserName+' - Pass')
|
if(printResults) console.log('Test: Register User '+testUserName+' - Pass')
|
||||||
|
|
||||||
return User.getMasterKey(testUserId, password)
|
return User.getMasterKey(testUserId, password)
|
||||||
})
|
})
|
||||||
.then(newMasterKey => {
|
.then(newMasterKey => {
|
||||||
masterKey = newMasterKey
|
masterKey = newMasterKey
|
||||||
@ -453,6 +571,26 @@ User.keyPairTest = (testUserName = 'genMan', password = '1', printResults) => {
|
|||||||
|
|
||||||
if(printResults) console.log('Test: Login New User - Pass')
|
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})
|
resolve({testUserId, masterKey})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -6,9 +6,8 @@ let QuickNote = require('@models/QuickNote');
|
|||||||
let userId = null
|
let userId = null
|
||||||
let masterKey = null
|
let masterKey = null
|
||||||
|
|
||||||
// middleware that is specific to this router
|
|
||||||
router.use(function setUserId (req, res, next) {
|
router.use(function setUserId (req, res, next) {
|
||||||
if(userId = req.headers.userId){
|
if(req.headers.userId){
|
||||||
userId = req.headers.userId
|
userId = req.headers.userId
|
||||||
masterKey = req.headers.masterKey
|
masterKey = req.headers.masterKey
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
var express = require('express')
|
var express = require('express')
|
||||||
var router = express.Router()
|
var router = express.Router()
|
||||||
|
|
||||||
let User = require('@models/User');
|
const User = require('@models/User')
|
||||||
|
const Auth = require('@helpers/Auth')
|
||||||
const cs = require('@helpers/CryptoString')
|
const cs = require('@helpers/CryptoString')
|
||||||
|
|
||||||
// middleware that is specific to this router
|
// middleware that is specific to this router
|
||||||
@ -9,26 +10,14 @@ router.use(function timeLog (req, res, next) {
|
|||||||
// console.log('Time: ', Date.now())
|
// console.log('Time: ', Date.now())
|
||||||
next()
|
next()
|
||||||
})
|
})
|
||||||
// define the home page route
|
|
||||||
router.get('/', function (req, res) {
|
|
||||||
res.send('User Home Page ' + User.getUsername())
|
|
||||||
})
|
|
||||||
// define the about route
|
|
||||||
router.get('/about', function (req, res) {
|
|
||||||
User.getUsername(req.headers.userId)
|
|
||||||
.then( data => res.send(data) )
|
|
||||||
})
|
|
||||||
// Login User
|
// Login User
|
||||||
router.post('/login', function (req, res) {
|
router.post('/login', function (req, res) {
|
||||||
|
|
||||||
User.login(req.body.username, req.body.password)
|
User.login(req.body.username, req.body.password, req.body.authToken)
|
||||||
.then( returnData => {
|
.then( returnData => {
|
||||||
|
|
||||||
res.send(returnData)
|
res.send(returnData)
|
||||||
})
|
})
|
||||||
.catch(e => {
|
|
||||||
res.send(false)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
// Logout User
|
// Logout User
|
||||||
router.post('/logout', function (req, res) {
|
router.post('/logout', function (req, res) {
|
||||||
@ -39,10 +28,7 @@ router.post('/logout', function (req, res) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Register User
|
||||||
|
|
||||||
|
|
||||||
// Login User
|
|
||||||
router.post('/register', function (req, res) {
|
router.post('/register', function (req, res) {
|
||||||
|
|
||||||
User.register(req.body.username, req.body.password)
|
User.register(req.body.username, req.body.password)
|
||||||
@ -55,6 +41,24 @@ 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
|
// fetch counts of users notes
|
||||||
router.post('/totals', function (req, res) {
|
router.post('/totals', function (req, res) {
|
||||||
@ -62,5 +66,30 @@ router.post('/totals', function (req, res) {
|
|||||||
.then( countsObject => res.send( countsObject ))
|
.then( countsObject => res.send( countsObject ))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//
|
||||||
|
// Two Factor Auth Setup
|
||||||
|
//
|
||||||
|
router.post('/twofactorsetup', function (req, res) {
|
||||||
|
|
||||||
|
//Send QR code to user for 2FA setup
|
||||||
|
Auth.generateTwoFactorSecretKey(req.headers.userId, req.body.password)
|
||||||
|
.then( ({ qrCode }) => { res.send( qrCode ) })
|
||||||
|
})
|
||||||
|
|
||||||
|
router.post('/verifytwofactorsetuptoken', function (req, res) {
|
||||||
|
|
||||||
|
//Verify Users QR code with token
|
||||||
|
Auth.setTwoFactorEnabled(req.headers.userId, req.body.password, req.body.token, true)
|
||||||
|
.then( ( results ) => { res.send( results ) })
|
||||||
|
})
|
||||||
|
|
||||||
|
router.post('/validatetwofactortoken', function (req, res) {
|
||||||
|
|
||||||
|
//Verify Users QR code with token
|
||||||
|
Auth.validateTwoFactorToken(req.headers.userId, req.body.password, req.body.token)
|
||||||
|
.then( ( results ) => { res.send( results ) })
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = router
|
module.exports = router
|
Loading…
Reference in New Issue
Block a user