From f2a441061bb5b96d3b90faa580d2ea2b5fb1266f Mon Sep 17 00:00:00 2001
From: Wu Cheng-Han <jacky_cute0808@hotmail.com>
Date: Sun, 15 Jan 2017 17:23:19 +0800
Subject: [PATCH 1/9] Fix checkLoginStateChanged might fall into infinite loop
 while calling loginStateChangeEvent

---
 public/js/common.js | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/public/js/common.js b/public/js/common.js
index f5bfc8e..7eee107 100644
--- a/public/js/common.js
+++ b/public/js/common.js
@@ -18,7 +18,8 @@ var checkAuth = false;
 var profile = null;
 var lastLoginState = getLoginState();
 var lastUserId = getUserId();
-var loginStateChangeEvent = null;
+
+window.loginStateChangeEvent = null;
 
 function resetCheckAuth() {
     checkAuth = false;
@@ -42,8 +43,7 @@ function setLoginState(bool, id) {
 
 function checkLoginStateChanged() {
     if (getLoginState() != lastLoginState || getUserId() != lastUserId) {
-        if(loginStateChangeEvent)
-            loginStateChangeEvent();
+        if(loginStateChangeEvent) setTimeout(loginStateChangeEvent, 100);
         return true;
     } else {
         return false;
@@ -65,8 +65,7 @@ function clearLoginState() {
 
 function checkIfAuth(yesCallback, noCallback) {
     var cookieLoginState = getLoginState();
-    if (checkLoginStateChanged())
-        checkAuth = false;
+    if (checkLoginStateChanged()) checkAuth = false;
     if (!checkAuth || typeof cookieLoginState == 'undefined') {
         $.get(serverurl + '/me')
             .done(function (data) {
@@ -107,7 +106,6 @@ module.exports = {
     profile: profile,
     lastLoginState: lastLoginState,
     lastUserId: lastUserId,
-    loginStateChangeEvent: loginStateChangeEvent,
 
     /* export functions */
     resetCheckAuth: resetCheckAuth,

From 5751578275bd505ea613c77ab997a6ee29b1c1ee Mon Sep 17 00:00:00 2001
From: Wu Cheng-Han <jacky_cute0808@hotmail.com>
Date: Sun, 15 Jan 2017 17:23:33 +0800
Subject: [PATCH 2/9] Update to remove history pagination animation on refresh

---
 public/js/cover.js | 2 --
 1 file changed, 2 deletions(-)

diff --git a/public/js/cover.js b/public/js/cover.js
index a8d8ecf..15f3e9c 100644
--- a/public/js/cover.js
+++ b/public/js/cover.js
@@ -355,7 +355,6 @@ $(".ui-refresh-history").click(function () {
     $('.search').val('');
     historyList.search();
     $('#history-list').slideUp('fast');
-    $('.pagination').slideUp('fast');
 
     resetCheckAuth();
     historyList.clear();
@@ -367,7 +366,6 @@ $(".ui-refresh-history").click(function () {
         $('.search').val(lastKeyword);
         checkHistoryList();
         $('#history-list').slideDown('fast');
-        $('.pagination').slideDown('fast');
     });
 });
 

From f2ee8976997906f76fae39a5f5d7f70860f2c8dc Mon Sep 17 00:00:00 2001
From: Wu Cheng-Han <jacky_cute0808@hotmail.com>
Date: Mon, 16 Jan 2017 12:04:11 +0800
Subject: [PATCH 3/9] Fix to prevent hash change on click nav item on index

---
 public/js/cover.js | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/public/js/cover.js b/public/js/cover.js
index 15f3e9c..7c63e91 100644
--- a/public/js/cover.js
+++ b/public/js/cover.js
@@ -91,14 +91,18 @@ $(".masthead-nav li").click(function () {
     $(this).addClass("active");
 });
 
-$(".ui-home").click(function () {
+$(".ui-home").click(function (e) {
+    e.preventDefault();
+    e.stopPropagation();
     if (!$("#home").is(':visible')) {
         $(".section:visible").hide();
         $("#home").fadeIn();
     }
 });
 
-$(".ui-history").click(function () {
+$(".ui-history").click(function (e) {
+    e.preventDefault();
+    e.stopPropagation();
     if (!$("#history").is(':visible')) {
         $(".section:visible").hide();
         $("#history").fadeIn();

From 53223b5e2c9bb53737a4f812e61e0790833781db Mon Sep 17 00:00:00 2001
From: Wu Cheng-Han <jacky_cute0808@hotmail.com>
Date: Mon, 16 Jan 2017 12:06:04 +0800
Subject: [PATCH 4/9] Update index layout to add profile on navbar

---
 public/css/cover.css   | 22 ++++++++++++++++++---
 public/views/index.ejs | 44 +++++++++++++++++++++++-------------------
 2 files changed, 43 insertions(+), 23 deletions(-)

diff --git a/public/css/cover.css b/public/css/cover.css
index dcf7321..a1527bf 100644
--- a/public/css/cover.css
+++ b/public/css/cover.css
@@ -78,6 +78,13 @@ body {
     margin-top: 10px;
     margin-bottom: 10px;
 }
+.masthead-nav {
+    text-align: left;
+    max-width: 1000px;
+    margin: 0 auto;
+    padding-left: 10px;
+    padding-right: 10px;
+}
 .masthead-nav > li {
     display: inline-block;
 }
@@ -263,9 +270,14 @@ input {
     text-decoration: underline;
 }
 .ui-avatar {
-    border-radius: 15em;
-    height: auto;
-    width: 60px;
+    display: inline-block;
+    overflow: hidden;
+    line-height: 1;
+    vertical-align: middle;
+    border-radius: 3px;
+}
+.ui-avatar.circle {
+    border-radius: 50%;
 }
 .ui-history-close {
     position: absolute;
@@ -338,6 +350,10 @@ input {
     display: inline-block !important;
 }
 
+.btn-link, .btn-link:hover, .btn-link:focus, .btn-link:active {
+    color: white;
+}
+
 select {
     color: black;
 }
diff --git a/public/views/index.ejs b/public/views/index.ejs
index 55c13d2..2513990 100644
--- a/public/views/index.ejs
+++ b/public/views/index.ejs
@@ -40,6 +40,25 @@
                                 </li>
                                 <li class="ui-history<% if(signin) { %> active<% } %>"><a href="#"><%= __('History') %></a>
                                 </li>
+                                <div class="ui-signin" style="float: right; margin-top: 8px;<% if(signin) { %> display: none;<% } %>">
+                                    <% if(allowAnonymous) { %>
+                                    <a type="button" href="<%- url %>/new" class="btn btn-sm btn-link"><i class="fa fa-plus"></i> <%= __('New guest note') %></a>
+                                    <% } %>
+                                    <% if(facebook || twitter || github || gitlab || dropbox || google || ldap || email) { %>
+                                    <button class="btn btn-sm btn-success ui-signin" data-toggle="modal" data-target=".signin-modal"><%= __('Sign In') %></button>
+                                    <% } %>
+                                </div>
+                                <div class="ui-signout" style="float: right; margin-top: 8px;<% if(!signin) { %> display: none;<% } %>">
+                                    <a type="button" href="<%- url %>/new" class="btn btn-sm btn-link"><i class="fa fa-plus"></i> <%= __('New note') %></a>
+                                    <span class="ui-profile dropdown pull-right">
+                                        <button id="profileLabel" class="btn btn-sm btn-link ui-profile-label" style="padding-right: 0;" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                                            <img class="ui-avatar" width="20" height="20"><span class="hidden-xs hidden-sm">&ensp;<span class="ui-name"></span></span>&ensp;<i class="fa fa-caret-down"></i>
+                                        </button>
+                                        <ul class="dropdown-menu" aria-labelledby="profileLabel">
+                                            <li><a href="<%- url %>/logout"><i class="fa fa-sign-out fa-fw"></i> <%= __('Sign Out') %></a></li>
+                                        </ul>
+                                    </span>
+                                </div>
                             </ul>
                         </nav>
                     </div>
@@ -60,19 +79,15 @@
                         <% if(facebook || twitter || github || gitlab || dropbox || google || ldap || email) { %>
                         <span class="ui-signin">
                             <br>
-                            <a type="button" class="btn btn-lg btn-success ui-signin" data-toggle="modal" data-target=".signin-modal" style="min-width: 170px;"><%= __('Sign In') %></a>
+                            <a type="button" class="btn btn-lg btn-success ui-signin" data-toggle="modal" data-target=".signin-modal" style="min-width: 200px;"><%= __('Sign In') %></a>
                         </span>
-                        <% }%>
-                        <% if((facebook || twitter || github || gitlab || dropbox || google || email) && allowAnonymous) { %>
                         <span class="ui-or"><%= __('or') %></span>
-                        <% }%>
-                        <% if(allowAnonymous) { %>
+                        <% } %>
                         <span class="ui-signin">
-                            <a href="<%- url %>/new" class="btn btn-lg btn-default" style="min-width: 170px;"><%= __('New guest note') %></a>
+                            <a type="button" href="<%- url %>/features" class="btn btn-lg btn-primary" style="min-width: 200px;"><%= __('Explore all features') %></a>
                             <br>
                             <br>
                         </span>
-                        <% }%>
                         <div class="lead row" style="width: 90%; margin: 0 auto;">
                             <div class="col-md-4 inner">
                                 <a href="<%- url %>/features#share-notes">
@@ -97,21 +112,10 @@
                 </div>
 
                 <div id="history" class="section"<% if(!signin) { %> style="display:none;"<% } %>>
-                    <% if(facebook || twitter || github || gitlab || dropbox || google || ldap || email) { %>
-                    <div class="ui-signin">
+                    <div class="ui-signin"<% if(signin) { %> style="display:none;"<% } %>>
                         <p><%= __('Below is the history from browser') %></p>
                     </div>
-                    <div class="ui-signout" style="display:none;">
-                        <img class="ui-avatar">
-                        <h4 class="ui-welcome"><%= __('Welcome!') %> <span class="ui-name"></span></h4>
-                        <a href="<%- url %>/new" class="btn btn-md btn-default"><%= __('New note') %></a> <%= __('or') %>
-                        <a href="#" class="btn btn-danger ui-logout"><%= __('Sign Out') %></a>
-                    </div>
-                    <% }%>
-                    <h4>
-                        <a type="button" href="<%- url %>/features" class="btn btn-primary"><%= __('Explore all features') %></a>
-                    </h4>
-                    <hr>
+                    <br>
                     <form class="form-inline">
                         <div class="form-group" style="vertical-align: bottom;">
                             <input class="form-control ui-use-tags" placeholder="<%= __('Select tags...') %>" />

From 091e7271e0e7e5df83516c471af34f4ae481d12a Mon Sep 17 00:00:00 2001
From: Wu Cheng-Han <jacky_cute0808@hotmail.com>
Date: Mon, 16 Jan 2017 12:24:40 +0800
Subject: [PATCH 5/9] Fix pagination should hide on refresh history

---
 public/js/cover.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/public/js/cover.js b/public/js/cover.js
index 7c63e91..52ff5a2 100644
--- a/public/js/cover.js
+++ b/public/js/cover.js
@@ -359,6 +359,7 @@ $(".ui-refresh-history").click(function () {
     $('.search').val('');
     historyList.search();
     $('#history-list').slideUp('fast');
+    $('.pagination').hide();
 
     resetCheckAuth();
     historyList.clear();

From 3c0667813cb1a3d5a0d730eabc70835b52518dfe Mon Sep 17 00:00:00 2001
From: Wu Cheng-Han <jacky_cute0808@hotmail.com>
Date: Mon, 16 Jan 2017 12:41:34 +0800
Subject: [PATCH 6/9] Fix missing config in hackmd response

---
 lib/response.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/response.js b/lib/response.js
index 9014a0a..57d6861 100755
--- a/lib/response.js
+++ b/lib/response.js
@@ -97,7 +97,8 @@ function responseHackMD(res, note) {
         dropbox: config.dropbox,
         google: config.google,
         ldap: config.ldap,
-        email: config.email
+        email: config.email,
+        allowemailregister: config.allowemailregister
     });
 }
 

From e00daee6c0dd0c6e5f2654d24995bc9d86fbc452 Mon Sep 17 00:00:00 2001
From: Wu Cheng-Han <jacky_cute0808@hotmail.com>
Date: Mon, 16 Jan 2017 12:42:21 +0800
Subject: [PATCH 7/9] Update to prevent all empty link change hash

---
 public/js/cover.js | 9 +++++----
 public/js/index.js | 4 ++++
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/public/js/cover.js b/public/js/cover.js
index 52ff5a2..f8ffe9b 100644
--- a/public/js/cover.js
+++ b/public/js/cover.js
@@ -91,9 +91,12 @@ $(".masthead-nav li").click(function () {
     $(this).addClass("active");
 });
 
-$(".ui-home").click(function (e) {
+// prevent empty link change hash
+$('a[href="#"]').click(function (e) {
     e.preventDefault();
-    e.stopPropagation();
+});
+
+$(".ui-home").click(function (e) {
     if (!$("#home").is(':visible')) {
         $(".section:visible").hide();
         $("#home").fadeIn();
@@ -101,8 +104,6 @@ $(".ui-home").click(function (e) {
 });
 
 $(".ui-history").click(function (e) {
-    e.preventDefault();
-    e.stopPropagation();
     if (!$("#history").is(':visible')) {
         $(".section:visible").hide();
         $("#history").fadeIn();
diff --git a/public/js/index.js b/public/js/index.js
index 14235bc..a018e51 100644
--- a/public/js/index.js
+++ b/public/js/index.js
@@ -1754,6 +1754,10 @@ ui.toolbar.uploadImage.bind('change', function (e) {
 ui.toc.dropdown.click(function (e) {
     e.stopPropagation();
 });
+// prevent empty link change hash
+$('a[href="#"]').click(function (e) {
+    e.preventDefault();
+});
 
 //modal actions
 var revisions = [];

From 14734372956fa5d6c6159ba8c4b00a90b80ea8d6 Mon Sep 17 00:00:00 2001
From: Wu Cheng-Han <jacky_cute0808@hotmail.com>
Date: Mon, 16 Jan 2017 23:47:53 +0800
Subject: [PATCH 8/9] Refactor checkViewPermission to fix limited & protected
 permission check bug and fix code style

---
 lib/realtime.js | 48 ++++++++++++++++++++++++++++--------------------
 lib/response.js |  6 +++---
 2 files changed, 31 insertions(+), 23 deletions(-)

diff --git a/lib/realtime.js b/lib/realtime.js
index 0f2a668..fadea4f 100644
--- a/lib/realtime.js
+++ b/lib/realtime.js
@@ -363,6 +363,22 @@ function interruptConnection(socket, note, user) {
     connectNextSocket();
 }
 
+function checkViewPermission(req, note) {
+    if (note.permission == 'private') {
+        if (req.user && req.user.logged_in && req.user.id == note.owner)
+            return true;
+        else
+            return false;
+    } else if (note.permission == 'limited' || note.permission == 'protected') {
+        if(req.user && req.user.logged_in)
+            return true;
+        else
+            return false;
+    } else {
+        return true;
+    }
+}
+
 var isConnectionBusy = false;
 var connectionSocketQueue = [];
 var isDisconnectBusy = false;
@@ -373,14 +389,10 @@ function finishConnection(socket, note, user) {
     if (!socket || !note || !user) {
         return interruptConnection(socket, note, user);
     }
-    //check view permission
-    if (note.permission == 'limited' || note.permission == 'protected' || note.permission == 'private') {
-        if (socket.request.user && socket.request.user.logged_in && socket.request.user.id == note.owner) {
-            //na
-        } else {
-            interruptConnection(socket, note, user);
-            return failConnection(403, 'connection forbidden', socket);
-        }
+    // check view permission
+    if (!checkViewPermission(socket.request, note)) {
+        interruptConnection(socket, note, user);
+        return failConnection(403, 'connection forbidden', socket);
     }
     // update user color to author color
     if (note.authors[user.userid]) {
@@ -789,18 +801,14 @@ function connection(socket) {
                     for (var i = 0, l = note.socks.length; i < l; i++) {
                         var sock = note.socks[i];
                         if (typeof sock !== 'undefined' && sock) {
-                            //check view permission
-                            if (permission == 'limited' || permission == 'protected' || permission == 'private') {
-                                if (sock.request.user && sock.request.user.logged_in && sock.request.user.id == note.owner) {
-                                    //na
-                                } else {
-                                    sock.emit('info', {
-                                        code: 403
-                                    });
-                                    setTimeout(function () {
-                                        sock.disconnect(true);
-                                    }, 0);
-                                }
+                            // check view permission
+                            if (!checkViewPermission(sock.request, note)) {
+                                sock.emit('info', {
+                                    code: 403
+                                });
+                                setTimeout(function () {
+                                    sock.disconnect(true);
+                                }, 0);
                             }
                         }
                     }
diff --git a/lib/response.js b/lib/response.js
index 57d6861..585d1d5 100755
--- a/lib/response.js
+++ b/lib/response.js
@@ -127,10 +127,10 @@ function checkViewPermission(req, note) {
         else
             return true;
     } else if (note.permission == 'limited' || note.permission == 'protected') {
-        if( !req.isAuthenticated() ) {
+        if(!req.isAuthenticated())
             return false;
-        }
-        return true;
+        else
+            return true;
     } else {
         return true;
     }

From 20dc3127b106e18b41573299f75d75c6b77f958d Mon Sep 17 00:00:00 2001
From: Jan Kunzmann <jan-github@phobia.de>
Date: Fri, 20 Jan 2017 02:13:09 +0100
Subject: [PATCH 9/9] Handle SIGTERM the same way SIGINT is handled

---
 app.js | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/app.js b/app.js
index 7b5e619..ba0b67d 100644
--- a/app.js
+++ b/app.js
@@ -626,8 +626,8 @@ process.on('uncaughtException', function (err) {
     process.exit(1);
 });
 
-// gracefully exit
-process.on('SIGINT', function () {
+// install exit handler
+function handleTermSignals() {
     config.maintenance = true;
     // disconnect all socket.io clients
     Object.keys(io.sockets.sockets).forEach(function (key) {
@@ -649,4 +649,6 @@ process.on('SIGINT', function () {
             });
         }
     }, 100);
-});
+}
+process.on('SIGINT', handleTermSignals);
+process.on('SIGTERM', handleTermSignals);