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"> <span class="ui-name"></span></span> <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);