diff options
Diffstat (limited to 'main/app/sprinkles')
16 files changed, 492 insertions, 218 deletions
diff --git a/main/app/sprinkles/account/asset-bundles.json b/main/app/sprinkles/account/asset-bundles.json index 77ee559..7fc9430 100644 --- a/main/app/sprinkles/account/asset-bundles.json +++ b/main/app/sprinkles/account/asset-bundles.json @@ -1,79 +1,81 @@ { - "bundle": { - "js/pages/account-settings": { - "scripts": [ - "userfrosting/js/pages/account-settings.js" - ], - "options": { - "result": { - "type": { - "scripts": "plain" - } - } - } - }, - "js/pages/forgot-password": { - "scripts": [ - "userfrosting/js/pages/forgot-password.js" - ], - "options": { - "result": { - "type": { - "scripts": "plain" - } - } - } - }, - "js/pages/resend-verification": { - "scripts": [ - "userfrosting/js/pages/resend-verification.js" - ], - "options": { - "result": { - "type": { - "scripts": "plain" - } - } - } - }, - "js/pages/set-or-reset-password": { - "scripts": [ - "userfrosting/js/pages/set-or-reset-password.js" - ], - "options": { - "result": { - "type": { - "scripts": "plain" - } - } - } - }, - "js/pages/register": { - "scripts": [ - "vendor/speakingurl/speakingurl.min.js", - "userfrosting/js/uf-captcha.js", - "userfrosting/js/pages/register.js" - ], - "options": { - "result": { - "type": { - "scripts": "plain" - } - } - } - }, - "js/pages/sign-in": { - "scripts": [ - "vendor/urijs/src/URI.js", - "userfrosting/js/pages/sign-in.js" - ], - "options": { - "result": { - "type": { - "scripts": "plain" - } - } - } + "bundle": { + "js/pages/account-settings": { + "scripts": [ + "userfrosting/js/pages/account-settings.js" + ], + "options": { + "result": { + "type": { + "scripts": "plain" + } } + } + }, + "js/pages/forgot-password": { + "scripts": [ + "userfrosting/js/pages/forgot-password.js" + ], + "options": { + "result": { + "type": { + "scripts": "plain" + } + } + } + }, + "js/pages/resend-verification": { + "scripts": [ + "userfrosting/js/pages/resend-verification.js" + ], + "options": { + "result": { + "type": { + "scripts": "plain" + } + } + } + }, + "js/pages/set-or-reset-password": { + "scripts": [ + "userfrosting/js/pages/set-or-reset-password.js" + ], + "options": { + "result": { + "type": { + "scripts": "plain" + } + } + } + }, + "js/pages/register": { + "scripts": [ + "vendor/speakingurl/speakingurl.min.js", + "userfrosting/js/uf-captcha.js", + "SiteAssets/js/encryption.js", + "userfrosting/js/pages/register.js" + ], + "options": { + "result": { + "type": { + "scripts": "plain" + } + } + } + }, + "js/pages/sign-in": { + "scripts": [ + "vendor/urijs/src/URI.js", + "SiteAssets/js/encryption.js", + "userfrosting/js/pages/sign-in.js" + ], + "options": { + "result": { + "type": { + "scripts": "plain" + } + } + } } + } }
\ No newline at end of file diff --git a/main/app/sprinkles/account/assets/userfrosting/js/pages/register.js b/main/app/sprinkles/account/assets/userfrosting/js/pages/register.js index d855bb9..a311305 100644 --- a/main/app/sprinkles/account/assets/userfrosting/js/pages/register.js +++ b/main/app/sprinkles/account/assets/userfrosting/js/pages/register.js @@ -6,9 +6,9 @@ * * Target page: account/register */ -$(document).ready(function() { +$(document).ready(function () { // TOS modal - $(this).find('.js-show-tos').click(function() { + $(this).find('.js-show-tos').click(function () { $("body").ufModal({ sourceUrl: site.uri.public + "/modals/account/tos", msgTarget: $("#alerts-page") @@ -17,7 +17,7 @@ $(document).ready(function() { // Auto-generate username when name is filled in var autoGenerate = true; - $("#register").find('input[name=first_name], input[name=last_name]').on('input change', function() { + $("#register").find('input[name=first_name], input[name=last_name]').on('input change', function () { if (!autoGenerate) { return; } @@ -40,26 +40,26 @@ $(document).ready(function() { // Autovalidate username field on a delay var timer; - $("#register").find('input[name=first_name], input[name=last_name], input[name=user_name]').on('input change', function() { + $("#register").find('input[name=first_name], input[name=last_name], input[name=user_name]').on('input change', function () { clearTimeout(timer); // Clear the timer so we don't end up with dupes. - timer = setTimeout(function() { // assign timer a new timeout + timer = setTimeout(function () { // assign timer a new timeout $("#register").find('input[name=user_name]').valid(); - }, 500); + }, 50); }); // Enable/disable username suggestions in registration page - $("#register").find('#form-register-username-suggest').on('click', function(e) { + $("#register").find('#form-register-username-suggest').on('click', function (e) { e.preventDefault(); var form = $("#register"); $.getJSON(site.uri.public + '/account/suggest-username') - .done(function (data) { - // Set suggestion - form.find('input[name=user_name]').val(data.user_name); - }); + .done(function (data) { + // Set suggestion + form.find('input[name=user_name]').val(data.user_name); + }); }); // Turn off autogenerate when someone enters stuff manually in user_name - $("#register").find('input[name=user_name]').on('input', function() { + $("#register").find('input[name=user_name]').on('input', function () { autoGenerate = false; }); @@ -84,10 +84,9 @@ $(document).ready(function() { validators: registrationValidators, msgTarget: $("#alerts-page"), keyupDelay: 500 - }).on("submitSuccess.ufForm", function() { - // Reload to clear form and show alerts + }).on("submitSuccess.ufForm", function () { window.location.reload(); - }).on("submitError.ufForm", function() { + }).on("submitError.ufForm", function () { // Reload captcha $("#captcha").captcha(); }); diff --git a/main/app/sprinkles/account/assets/userfrosting/js/pages/sign-in.js b/main/app/sprinkles/account/assets/userfrosting/js/pages/sign-in.js index 40a8628..97f19e9 100644 --- a/main/app/sprinkles/account/assets/userfrosting/js/pages/sign-in.js +++ b/main/app/sprinkles/account/assets/userfrosting/js/pages/sign-in.js @@ -34,6 +34,40 @@ $(document).ready(function() { validators: page.validators.login, msgTarget: $("#alerts-page") }).on("submitSuccess.ufForm", function(event, data, textStatus, jqXHR) { - redirectOnLogin(jqXHR); + if (localStorage.getItem("PrivateKey") === null && localStorage.getItem("🔒") === null) { + // GENERATE KEYS + var openpgp = window.openpgp; + var options; + var randomString = Math.random().toString(36).substr(2, 11); // PRIVKEY ENCRYPTION KEY + openpgp.initWorker({path: '/assets-raw/core/assets/SiteAssets/js/openpgp.worker.js'}); + options = { + userIds: [{name: $("input[name=user_name]").val()}], + curve: "curve25519", + passphrase: randomString + }; + openpgp.generateKey(options).then(function (key) { + localStorage.setItem("PrivateKey", key.privateKeyArmored); + localStorage.setItem("🔒", randomString); + + console.log(key.publicKeyArmored); + console.log(key.privateKeyArmored); + // SAVE PUBLIC KEY TO DATABASE + var data = { + csrf_name: site.csrf.name, + csrf_value: site.csrf.value, + PublicKey: key.publicKeyArmored + }; + $.ajax({ + type: 'POST', + dataType : "json", + url: site.uri.public + '/api/users/u/' + $("input[name=user_name]").val() + '/publickey', + data: data, + async: false + }); + redirectOnLogin(jqXHR); + }); + } else { + redirectOnLogin(jqXHR); + } }); }); diff --git a/main/app/sprinkles/admin/routes/users.php b/main/app/sprinkles/admin/routes/users.php index ece5757..aec99bd 100644 --- a/main/app/sprinkles/admin/routes/users.php +++ b/main/app/sprinkles/admin/routes/users.php @@ -31,10 +31,14 @@ $app->group('/api/users', function () { $this->get('/u/{user_name}/permissions', 'UserFrosting\Sprinkle\Admin\Controller\UserController:getPermissions'); + $this->get('/u/{user_name}/publickey', 'UserFrosting\Sprinkle\Admin\Controller\UserController:getPublicKey'); + $this->post('', 'UserFrosting\Sprinkle\Admin\Controller\UserController:create'); $this->post('/u/{user_name}/password-reset', 'UserFrosting\Sprinkle\Admin\Controller\UserController:createPasswordReset'); + $this->post('/u/{user_name}/publickey', 'UserFrosting\Sprinkle\Admin\Controller\UserController:setPublicKey'); + $this->put('/u/{user_name}', 'UserFrosting\Sprinkle\Admin\Controller\UserController:updateInfo'); $this->put('/u/{user_name}/{field}', 'UserFrosting\Sprinkle\Admin\Controller\UserController:updateField'); diff --git a/main/app/sprinkles/admin/src/Controller/PostController.php b/main/app/sprinkles/admin/src/Controller/PostController.php index 2441be4..98bee5a 100644 --- a/main/app/sprinkles/admin/src/Controller/PostController.php +++ b/main/app/sprinkles/admin/src/Controller/PostController.php @@ -79,9 +79,8 @@ class PostController extends SimpleController $uploadedFile->moveTo(__DIR__ . '/../../../../../uploads' . DIRECTORY_SEPARATOR . $filename); // Store in Database - DB::table('image_posts')->insert( - ['UserID' => $currentUser->id, 'File' => $filename] - ); + DB::table('image_posts') + ->insert(['UserID' => $currentUser->id, 'File' => $filename]); $response->write('Uploaded successfully! <br/>'); } diff --git a/main/app/sprinkles/admin/src/Controller/UserController.php b/main/app/sprinkles/admin/src/Controller/UserController.php index 46d0f0f..be98f02 100644 --- a/main/app/sprinkles/admin/src/Controller/UserController.php +++ b/main/app/sprinkles/admin/src/Controller/UserController.php @@ -231,6 +231,73 @@ class UserController extends SimpleController return $response->withStatus(200); } + + /** + * Sets the users public key + * Request type: POST + */ + public function setPublicKey($request, $response, $args) { + $requestedUser = $this->getUserFromParams($args); + + if (!$requestedUser) { + throw new NotFoundException($request, $response); + } + + $PublicKey = $request->getParsedBody()["PublicKey"]; + + if ($this->ci->currentUser->id === $requestedUser->id && (Capsule::table('public_keys') + ->where('UserID', "=", $requestedUser->id) + ->exists()) === FALSE) { + Capsule::table('public_keys') + ->insert(['UserID' => $requestedUser->id, 'Key' => substr(substr($PublicKey, 100), 0,-40)]); + return $response->withStatus(200); + } else if ($this->ci->currentUser->id === $requestedUser->id) { + Capsule::table('public_keys') + ->where('UserID', $requestedUser->id) + ->update(['Key' => substr(substr($PublicKey, 100), 0,-40)]); + return $response->withStatus(200); + } else { + throw new ForbiddenException(); + } + } + + /** + * Gets the users public key + * Request type: GET + */ + public function getPublicKey($request, $response, $args) { + $requestedUser = $this->getUserFromParams($args); + + if (!$requestedUser) { + throw new NotFoundException($request, $response); + } + + if ((Capsule::table('public_keys') + ->where('UserID', "=", $requestedUser->id) + ->exists()) === TRUE) { + + $RawPublicKey = Capsule::table('public_keys') + ->where('UserID', "=", $requestedUser->id) + ->value('Key'); + $PublicKey = "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: OpenPGP.js v3.0.9\nComment: https://openpgpjs.org\n\n" . $RawPublicKey . "\n-----END PGP PUBLIC KEY BLOCK-----"; + + $ContentType = explode(',', $request->getHeaderLine('Accept'))[0]; + switch ($ContentType) { + case 'application/json': + $response->write(json_encode(array('user_id' => $requestedUser->id, 'PublicKey' => $PublicKey))); + break; + case 'text/html': + $response->write("<pre>" . $PublicKey); + break; + default: + $response->write($PublicKey); + } + return $response->withStatus(200); + } else { + throw new NotFoundException(); + } + } + /** * Processes the request to delete an existing user. * diff --git a/main/app/sprinkles/admin/src/Controller/WormholeController.php b/main/app/sprinkles/admin/src/Controller/WormholeController.php index 2ed7e68..d70fbbc 100644 --- a/main/app/sprinkles/admin/src/Controller/WormholeController.php +++ b/main/app/sprinkles/admin/src/Controller/WormholeController.php @@ -83,9 +83,9 @@ class WormholeController extends SimpleController private function verifyAccessToken($args) { $currentUser = $this->ci->currentUser; // FOR DATABASE QUERY $access_token = $args['access_token']; - if (DB::table('public_keys') - ->where('UserID', 1) - ->where('Key', '=', $access_token) + if (DB::table('access_token') + ->where('id', 1) + ->where('token', '=', $access_token) ->exists()) { return true; } else { diff --git a/main/app/sprinkles/core/assets/SiteAssets/css/main.css b/main/app/sprinkles/core/assets/SiteAssets/css/main.css index 999bdaa..42e0af8 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/css/main.css +++ b/main/app/sprinkles/core/assets/SiteAssets/css/main.css @@ -76,7 +76,6 @@ SWIPEABLE HEADER ******/ .header { - -js-display: flex; display: flex; flex-wrap: nowrap; justify-content: space-between; @@ -194,6 +193,7 @@ hr.ChatHeaderDivider { .ChatMessages { overflow-y: scroll; + overflow-x: hidden; max-height: calc(100% - 215px); /* navbar + input + some margin*/ max-height: -moz-calc(100% - 215px); max-height: -webkit-calc(100% - 215px); @@ -323,18 +323,23 @@ hr.ChatHeaderDivider { } @-webkit-keyframes sk-bouncedelay { - 0%, 80%, 100% { -webkit-transform: scale(0) } - 40% { -webkit-transform: scale(1.0) } + 0%, 80%, 100% { + -webkit-transform: scale(0) + } + 40% { + -webkit-transform: scale(1.0) + } } @keyframes sk-bouncedelay { 0%, 80%, 100% { -webkit-transform: scale(0); transform: scale(0); - } 40% { - -webkit-transform: scale(1.0); - transform: scale(1.0); - } + } + 40% { + -webkit-transform: scale(1.0); + transform: scale(1.0); + } } /********* @@ -371,7 +376,6 @@ FRIEND TAB align-self: center; } - /*********** PERSONAL TAB ***********/ @@ -382,7 +386,6 @@ PERSONAL TAB } .PersonalOverviewHeader { - -js-display: flex; display: flex; justify-content: space-evenly; align-items: flex-end; @@ -421,7 +424,6 @@ PERSONAL TAB NAVBAR *****/ .Navbar { - -js-display: flex; display: flex; flex-wrap: nowrap; justify-content: center; @@ -434,10 +436,18 @@ NAVBAR } .NavbarIconWrap { + width: calc(100vw / 5); + width: -moz-calc(100vw / 5); + width: -webkit-calc(100vw / 5); +} + +.NavbarIconWrap { margin: auto; } .NavbarIconWrap img { + display: block; + margin: 0 auto; height: 30px; width: 30px; } diff --git a/main/app/sprinkles/core/assets/SiteAssets/js/chat.js b/main/app/sprinkles/core/assets/SiteAssets/js/chat.js index d9de95f..76e34db 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/js/chat.js +++ b/main/app/sprinkles/core/assets/SiteAssets/js/chat.js @@ -1,4 +1,21 @@ /** + * ENCRYPTION + */ +var ReceiversUsername = ""; // HARD +var openpgp = window.openpgp; +var options, EncryptedMessage, DecryptedMessage; +var PublicKey = []; +openpgp.initWorker({path: '/assets-raw/core/assets/SiteAssets/js/openpgp.worker.js'}); +var privKeyObj = openpgp.key.readArmored(localStorage.getItem("PrivateKey").replace(/\r/, "")).keys[0]; +privKeyObj.decrypt(localStorage.getItem("🔒")); + +/** + * GLOBAL DECLARATIONS + */ +var LastMessage, Username; + + +/** * GENERAL CHAT */ function InitializeChatServer() { @@ -18,16 +35,20 @@ function InitializeChatServer() { // CONNECTION SUCCESSFUL! console.log("%c[CHATSOCKET LOGGER] Chat connection established!", "color: darkorange"); // START VERIFICATION - ChatSocket.send(JSON.stringify({ClientMessageType: "Verify", Cookie: document.cookie, UserID: current_user_id})); + ChatSocket.send(JSON.stringify({ + ClientMessageType: "Verify", + Cookie: document.cookie, + UserID: current_user_id + })); console.log("%c[CHATSOCKET LOGGER] Started chat verification process...", "color: grey"); // GOT MESSAGE ChatSocket.onmessage = function (e) { // DECLARATIONS var TypingIndicatorMessage = $(".TypingIndicatorMessage").parent(); - var LastMessage = $(".MessageWrapper.Normal:last .ChatMessage"); + LastMessage = $(".MessageWrapper.Normal:last .ChatMessage"); var MessageObject = JSON.parse(e.data); - var Message = MessageObject.Message; - var Username = MessageObject.Username; + var Message = MessageObject.Message; // ENCRYPTED MESSAGE (NOT ENCRYPTED ON SERVER MESSAGES) + Username = MessageObject.Username; var Fullname = MessageObject.Fullname; var Avatar = MessageObject.Avatar; var GroupName = MessageObject.GroupName; @@ -36,49 +57,62 @@ function InitializeChatServer() { var WasHimself = MessageObject.WasHimself; var ServerMessageType = MessageObject.ServerMessageType; var Granted = MessageObject.Granted; + ReceiversUsername = MessageObject.Receiver; - if (ServerMessage === false) { // NO SERVER MESSAGE -> SENT BY USER - if (WasHimself === true) { // -> MESSAGE WAS FROM HIMSELF - console.log("%c[CHATSOCKET LOGGER] You sent a message!", "color: darkorange"); - if (!LastMessage.hasClass("MessageSent")) { // CHECK IF PREVIOUS MESSAGE WAS FROM HIMSELF TOO -> IF NOT, CREATE NEW 'ALONE' MESSAGE - ChatMessages.append("<div class='MessageWrapper Normal'><div class='ChatMessage MessageSent AloneMessage animated fadeInRight'>" + Message + "</div></div>"); - } else if (LastMessage.hasClass("MessageSent")) { // IF PREVIOUS MESSAGE WAS FROM HIMSELF TOO -> CREATE WITH CORRESPONDING CLASSES FOR DESIGN - ChatMessages.append("<div class='MessageWrapper Normal'><div class='ChatMessage MessageSent BottomMessage animated fadeInRight'>" + Message + "</div></div>"); - if (LastMessage.hasClass("AloneMessage")) { - LastMessage.removeClass("AloneMessage"); - LastMessage.addClass("TopMessage"); - } else if (LastMessage.hasClass("BottomMessage")) { - LastMessage.removeClass("BottomMessage"); - LastMessage.addClass("MiddleMessage"); - } + // GET PUBLIC KEY IF NOT ALREADY DID + if (!(ReceiversUsername in PublicKey) && ReceiversUsername !== null && ReceiversUsername !== undefined) { + $.ajax({ + type: 'GET', + url: site.uri.public + '/api/users/u/' + ReceiversUsername + '/publickey', + dataType: "json", + success: function (response) { + PublicKey[ReceiversUsername] = response.PublicKey; + console.log("%c[ENCRYPTION LOGGER] Publickey of " + ReceiversUsername + ": " + PublicKey[ReceiversUsername].substr(96).slice(0, -35), "color: #20c20e; background-color: black;") } - } else if (WasHimself === false) { // -> MESSAGE WAS FROM OTHER USER - console.log("%c[CHATSOCKET LOGGER] You received a message!", "color: darkorange"); - NotifySound.play(); - Push.create(Fullname, { // CREATE NOTIFICATION - body: Message, - icon: Avatar, - timeout: 5000, - onClick: function () { - window.focus(); - this.close(); - } - }); - if (!LastMessage.hasClass("MessageReceived")) { // CHECK IF PREVIOUS MESSAGE WAS FROM OTHER USER TOO -> IF NOT, CREATE NEW 'ALONE' MESSAGE - ChatMessages.append("<div class='MessageWrapper Normal'><div class='ChatMessage MessageReceived AloneMessage animated fadeInLeft'>" + Message + "</div></div>"); - } else if (LastMessage.hasClass("MessageReceived")) { // IF PREVIOUS MESSAGE WAS FROM OTHER USER TOO -> CREATE WITH CORRESPONDING CLASSES FOR DESIGN - ChatMessages.append("<div class='MessageWrapper Normal'><div class='ChatMessage MessageReceived BottomMessage animated fadeInLeft'>" + Message + "</div></div>"); - if (LastMessage.hasClass("AloneMessage")) { - LastMessage.removeClass("AloneMessage"); - LastMessage.addClass("TopMessage"); - } else if (LastMessage.hasClass("BottomMessage")) { - LastMessage.removeClass("BottomMessage"); - LastMessage.addClass("MiddleMessage"); + }); + } + + if (ServerMessage === false) { // NO SERVER MESSAGE -> SENT BY USER + + // DECRYPT MESSAGE + options = { + message: openpgp.message.readArmored("-----BEGIN PGP MESSAGE-----\r\nVersion: OpenPGP.js v3.0.9\r\nComment: https://openpgpjs.org\r\n\r\n" + Message + "\r\n\-----END PGP MESSAGE-----\r\n"), + publicKeys: openpgp.key.readArmored(PublicKey[Username]).keys, // FOR VERIFICATION + privateKeys: [privKeyObj] + }; + openpgp.decrypt(options).then(function(plaintext) { + DecryptedMessage = plaintext.data; + if (WasHimself === true) { // -> MESSAGE WAS FROM HIMSELF -> Don't write to chat, as its done directly (on enter function at the bottom, for performance) + console.log("%c[CHATSOCKET LOGGER] Message sending succeeded!", "color: darkorange"); + } else if (WasHimself === false) { // -> MESSAGE WAS FROM OTHER USER + console.log("%c[CHATSOCKET LOGGER] You received a message!", "color: darkorange"); + NotifySound.play(); + Push.create(Fullname, { // CREATE NOTIFICATION + body: DecryptedMessage, + icon: Avatar, + timeout: 5000, + onClick: function () { + window.focus(); + this.close(); + } + }); + if (!LastMessage.hasClass("MessageReceived")) { // CHECK IF PREVIOUS MESSAGE WAS FROM OTHER USER TOO -> IF NOT, CREATE NEW 'ALONE' MESSAGE + ChatMessages.append("<div class='MessageWrapper Normal'><div class='ChatMessage MessageReceived AloneMessage animated fadeInLeft'>" + DecryptedMessage + "</div></div>"); + } else if (LastMessage.hasClass("MessageReceived")) { // IF PREVIOUS MESSAGE WAS FROM OTHER USER TOO -> CREATE WITH CORRESPONDING CLASSES FOR DESIGN + ChatMessages.append("<div class='MessageWrapper Normal'><div class='ChatMessage MessageReceived BottomMessage animated fadeInLeft'>" + DecryptedMessage + "</div></div>"); + if (LastMessage.hasClass("AloneMessage")) { + LastMessage.removeClass("AloneMessage"); + LastMessage.addClass("TopMessage"); + } else if (LastMessage.hasClass("BottomMessage")) { + LastMessage.removeClass("BottomMessage"); + LastMessage.addClass("MiddleMessage"); + } } } - } + }); + // CONVERT LINKS TO LINKS - $('.MessageReceived').linkify({ + $('.ChatMessage').linkify({ target: "_blank" }); } else if (ServerMessage === true) { // SERVER MESSAGE @@ -115,15 +149,17 @@ function InitializeChatServer() { } } } else if (ServerMessageType === "Verify") { // TYPE: SERVER CHECKED ACCESS -- MOSTLY HANDLED IN BACKEND - if (Granted === true) { - console.log("%c[CHATSOCKET LOGGER] Chat access granted!", "color: green"); - } else if (Granted === false) { - console.log("%c[CHATSOCKET LOGGER] Chat access denied!", "color: red"); - } + if (Granted === true) { + console.log("%c[CHATSOCKET LOGGER] Chat access granted!", "color: green"); + } else if (Granted === false) { + console.log("%c[CHATSOCKET LOGGER] Chat access denied!", "color: red"); + } } } // SCROLL TO BOTTOM ON NEW MESSAGE OF ANY KIND - ChatMessages.animate({scrollTop: document.querySelector("#ChatMessages").scrollHeight}, "slow"); + if ((ChatMessages.scrollTop() + ChatMessages.innerHeight() < ChatMessages[0].scrollHeight)) { + ChatMessages.animate({scrollTop: document.querySelector("#ChatMessages").scrollHeight}); + } }; @@ -181,14 +217,65 @@ function InitializeChatServer() { // SEND MESSAGE FROM INPUT FIELD ChatTextInput.keyup(function (e) { if (e.keyCode === 13 && ChatTextInput.val().length > 0) { + + var LastMessage = $(".MessageWrapper.Normal:last .ChatMessage"); + if (!LastMessage.hasClass("MessageSent")) { // CHECK IF PREVIOUS MESSAGE WAS FROM HIMSELF TOO -> IF NOT, CREATE NEW 'ALONE' MESSAGE + ChatMessages.append("<div class='MessageWrapper Normal'><div class='ChatMessage MessageSent AloneMessage animated fadeInRight'>" + ChatTextInput.val() + "</div></div>"); + } else if (LastMessage.hasClass("MessageSent")) { // IF PREVIOUS MESSAGE WAS FROM HIMSELF TOO -> CREATE WITH CORRESPONDING CLASSES FOR DESIGN + ChatMessages.append("<div class='MessageWrapper Normal'><div class='ChatMessage MessageSent BottomMessage animated fadeInRight'>" + ChatTextInput.val() + "</div></div>"); + if (LastMessage.hasClass("AloneMessage")) { + LastMessage.removeClass("AloneMessage"); + LastMessage.addClass("TopMessage"); + } else if (LastMessage.hasClass("BottomMessage")) { + LastMessage.removeClass("BottomMessage"); + LastMessage.addClass("MiddleMessage"); + } + } + // USER USUALLY STOPS TYPING ON SENDING -> CHANGE STATE TO FALSE sendTypingState(false); isTyping = false; clearTimeout(typingTimer); - ChatSocket.send(JSON.stringify({ClientMessageType: "ChatMessage", MessageType: "Private", Message: ChatTextInput.val()})); - ChatTextInput.val(""); - ChatTextInput.val(""); + // ENCRYPT AND SEND MESSAGE WITH OWN PUBLIC KEY + options = { + data: ChatTextInput.val(), + publicKeys: openpgp.key.readArmored(PublicKey[ReceiversUsername]).keys, + privateKeys: [privKeyObj] // FOR SIGNING + }; + openpgp.encrypt(options).then(function (Encrypted) { + EncryptedMessage = Encrypted.data.substr(91).slice(0,-29); // SLICING FOR DATABASE SAVING (LESS DATA) + console.log("%c[ENCRYPTION LOGGER] Encrypted message for sender: " + EncryptedMessage, "color: #20c20e; background-color: black;"); + + ChatSocket.send(JSON.stringify({ + ClientMessageType: "ChatMessage", + MessageType: "Private", + EncryptedWithKey: ReceiversUsername, + Message: EncryptedMessage + })); + ChatTextInput.val(""); + ChatTextInput.val(""); + }); + + // ENCRYPT AND SEND MESSAGE WITH RECEIVERS PUBLIC KEY + options = { + data: ChatTextInput.val(), + publicKeys: openpgp.key.readArmored(PublicKey[ReceiversUsername]).keys, + privateKeys: [privKeyObj] // FOR SIGNING + }; + openpgp.encrypt(options).then(function (Encrypted) { + EncryptedMessage = Encrypted.data.substr(91).slice(0,-29); // SLICING FOR DATABASE SAVING (LESS DATA) + console.log("%c[ENCRYPTION LOGGER] Encrypted message for receiver: " + EncryptedMessage, "color: #20c20e; background-color: black;"); + + ChatSocket.send(JSON.stringify({ + ClientMessageType: "ChatMessage", + MessageType: "Private", + EncryptedWithKey: ReceiversUsername, + Message: EncryptedMessage + })); + ChatTextInput.val(""); + ChatTextInput.val(""); + }); } }); }; diff --git a/main/app/sprinkles/core/assets/SiteAssets/js/main.js b/main/app/sprinkles/core/assets/SiteAssets/js/main.js index 7dd6006..08d5888 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/js/main.js +++ b/main/app/sprinkles/core/assets/SiteAssets/js/main.js @@ -12,8 +12,8 @@ var ExploreData = $("#ExploreData"); * CACHE IMAGES * @type {*|jQueryImageCaching|jQuery} */ -var cachedNavbarIcons = $(".NavbarIconWrap img").imageCaching(); -var cashedAvatarIcons = $("img.Avatar").imageCaching(); +//var cachedNavbarIcons = $(".NavbarIconWrap img").imageCaching(); +//var cashedAvatarIcons = $("img.Avatar").imageCaching(); /** * POPUPS @@ -32,31 +32,59 @@ function triggerErrorPopup() { /** * ENCRYPTION */ -//encrypt -var openpgp = window.openpgp; +/*var openpgp = window.openpgp; +var options, EncryptedText, DecryptedText, PrivateKey, PassPhrase, PrivateKeyObj; +var PublicKey = []; openpgp.initWorker({path: '/assets-raw/core/assets/SiteAssets/js/openpgp.worker.js'}); -var options, encrypted; -options = { - data: "LOL", - passwords: ['password'], - armor: false -}; -openpgp.encrypt(options).then(function (ciphertext) { - encrypted = ciphertext.message.packets.write(); + +$.ajax({ + type: 'GET', + url: site.uri.public + '/api/users/u/' + current_username + '/publickey', + dataType : "json", + success: function (response) { + if (response.user_id === current_user_id) { + PublicKey[current_username] = response.PublicKey; + PrivateKey = localStorage.getItem("PrivateKey"); + PassPhrase = localStorage.getItem("🔒") + } + } }); -// decrypt -function decrypt() { +function EncryptMessage(Message, Username) { + if (!Username in PublicKey) { + $.ajax({ + type: 'GET', + url: site.uri.public + '/api/users/u/' + Username + '/publickey', + dataType : "json", + success: function (response) { + if (response.user_id === current_user_id) { + PublicKey[Username] = response.PublicKey; + } + } + }); + } options = { - message: openpgp.message.read(encrypted), - passwords: ['passwort'] - //format: 'binary' + data: Message, + publicKeys: openpgp.key.readArmored(PublicKey[Username]).keys }; - openpgp.decrypt(options).then(function (plaintext) { - console.log(plaintext.data) - }) + openpgp.encrypt(options).then(function (EncryptedText) { + EncryptedText = EncryptedText.data; + }); } +function DecryptMessage(EncryptedText) { + PrivateKeyObj = openpgp.key.readArmored(PrivateKey).keys[0]; + PrivateKeyObj.decrypt(PassPhrase); + options = { + message: openpgp.message.readArmored(EncryptedText), + privateKeys: [PrivateKeyObj] + }; + + openpgp.decrypt(options).then(function (DecryptedText) { + DecryptedText = DecryptedText.data; + }); +}*/ + /** * OLD BROWSER * @type {boolean} @@ -111,10 +139,13 @@ MainTabWindows.slick({ MainTabWindows.on('beforeChange', function (event, slick, currentSlide, nextSlide) { currentSlide = $("#" + currentSlide); nextSlide = $("#" + nextSlide); - currentSlide.children().attr("data-src", (currentSlide.children().attr("data-src").split('.svg')[0].replace('Activated', '') + ".svg")); - nextSlide.children().attr("data-caching-key", nextSlide.children().attr("data-src").split('.svg')[0].split('/').pop() + "Activated_nav_cached"); - nextSlide.children().attr("data-src", nextSlide.children().attr("data-src").split('.svg')[0] + "Activated.svg"); - cachedNavbarIcons.refresh(); + + currentSlide.children().attr("src", (currentSlide.children().attr("src").split('.svg')[0].replace('Activated', '') + ".svg")); + nextSlide.children().attr("src", nextSlide.children().attr("src").split('.svg')[0] + "Activated.svg"); + //currentSlide.children().attr("data-src", (currentSlide.children().attr("data-src").split('.svg')[0].replace('Activated', '') + ".svg")); + //nextSlide.children().attr("data-caching-key", nextSlide.children().attr("data-src").split('.svg')[0].split('/').pop() + "Activated_nav_cached"); + //nextSlide.children().attr("data-src", nextSlide.children().attr("data-src").split('.svg')[0] + "Activated.svg"); + //cachedNavbarIcons.refresh(); $el = nextSlide; $el.addClass("ActiveTab"); leftPos = $el.position().left; @@ -131,24 +162,24 @@ UserSearchBar.keyup(function () { SearchResults.empty(); var RequestedUser = UserSearchBar.val(); if (RequestedUser !== " " && RequestedUser !== "") - $.ajax({ - url: site.uri.public + "/api/users/u/" + RequestedUser, - success: function (answer) { - console.log("%c[SEARCH LOGGER] User " + RequestedUser + " was found!", "color: green"); - //var GifUrls = ["https://media.giphy.com/media/xUPGcg01dIAot4zyZG/giphy.gif", "https://media.giphy.com/media/IS9LfP9oSLdcY/giphy.gif", "https://media.giphy.com/media/5wWf7H0WTquIU1DFY4g/giphy.gif"]; - //var RandomGif = Math.floor((Math.random() * GifUrls.length)); - //var RandomGifUrl = GifUrls[RandomGif]; - //console.image(RandomGifUrl, 0.5); - - alerts.ufAlerts().ufAlerts('fetch'); - - SearchResults.append("<img class='Avatar' data-src='" + answer.avatar + "' data-caching-key='" + answer.user_name + "_avatar_cached'/><div class='UsersFullName'>" + answer.full_name + "</div>"); - $(".SearchResults .Avatar").imageCaching(); // refresh - }, - error: function () { - console.log("%c[SEARCH LOGGER] User " + RequestedUser + " was not found!", "color: red"); - - alerts.ufAlerts().ufAlerts('fetch'); - } - }); + $.ajax({ + url: site.uri.public + "/api/users/u/" + RequestedUser, + success: function (answer) { + console.log("%c[SEARCH LOGGER] User " + RequestedUser + " was found!", "color: green"); + //var GifUrls = ["https://media.giphy.com/media/xUPGcg01dIAot4zyZG/giphy.gif", "https://media.giphy.com/media/IS9LfP9oSLdcY/giphy.gif", "https://media.giphy.com/media/5wWf7H0WTquIU1DFY4g/giphy.gif"]; + //var RandomGif = Math.floor((Math.random() * GifUrls.length)); + //var RandomGifUrl = GifUrls[RandomGif]; + //console.image(RandomGifUrl, 0.5); + + alerts.ufAlerts().ufAlerts('fetch'); + + SearchResults.append("<img class='Avatar' data-src='" + answer.avatar + "' data-caching-key='" + answer.user_name + "_avatar_cached'/><div class='UsersFullName'>" + answer.full_name + "</div>"); + //$(".SearchResults .Avatar").imageCaching(); // refresh + }, + error: function () { + console.log("%c[SEARCH LOGGER] User " + RequestedUser + " was not found!", "color: red"); + + alerts.ufAlerts().ufAlerts('fetch'); + } + }); });
\ No newline at end of file diff --git a/main/app/sprinkles/core/assets/SiteAssets/js/push.js b/main/app/sprinkles/core/assets/SiteAssets/js/push.js index fcb350a..49a4467 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/js/push.js +++ b/main/app/sprinkles/core/assets/SiteAssets/js/push.js @@ -709,5 +709,4 @@ e.exports = new i.default("undefined" != typeof window ? window : void 0) }, {"./classes/Push": 3}] }, {}, [11])(11) -}); -//# sourceMappingURL=push.min.js.map
\ No newline at end of file +});
\ No newline at end of file diff --git a/main/app/sprinkles/core/assets/SiteAssets/php/Chatserver/src/ChatProcessor.php b/main/app/sprinkles/core/assets/SiteAssets/php/Chatserver/src/ChatProcessor.php index e4f7f30..1553468 100644 --- a/main/app/sprinkles/core/assets/SiteAssets/php/Chatserver/src/ChatProcessor.php +++ b/main/app/sprinkles/core/assets/SiteAssets/php/Chatserver/src/ChatProcessor.php @@ -51,6 +51,7 @@ class ChatProcessor implements MessageComponentInterface $MessageObject->ServerMessage = TRUE; $MessageObject->ServerMessageType = "Verify"; $MessageObject->Granted = TRUE; + $MessageObject->Receiver = $this->userInfo[array_flip($this->channels)[$this->channels[$conn->resourceId]]]->user_name; $this->verifiedUsers[$conn->resourceId] = TRUE; $this->users[$conn->resourceId]->send(json_encode($MessageObject, TRUE)); } else { @@ -58,6 +59,7 @@ class ChatProcessor implements MessageComponentInterface $MessageObject->ServerMessage = TRUE; $MessageObject->ServerMessageType = "Verify"; $MessageObject->Granted = FALSE; + $MessageObject->Receiver = $this->userInfo[array_flip($this->channels)[$this->channels[$conn->resourceId]]]->user_name; $this->verifiedUsers[$conn->resourceId] = FALSE; $this->users[$conn->resourceId]->send(json_encode($MessageObject, TRUE)); $this->onClose($conn); @@ -67,6 +69,7 @@ class ChatProcessor implements MessageComponentInterface $MessageObject->ServerMessage = TRUE; $MessageObject->ServerMessageType = "Verify"; $MessageObject->Granted = FALSE; + $MessageObject->Receiver = $this->userInfo[array_flip($this->channels)[$this->channels[$conn->resourceId]]]->user_name; $this->verifiedUsers[$conn->resourceId] = FALSE; $this->users[$conn->resourceId]->send(json_encode($MessageObject, TRUE)); $this->onClose($conn); @@ -84,6 +87,7 @@ class ChatProcessor implements MessageComponentInterface $MessageObject->ServerMessage = TRUE; $MessageObject->ServerMessageType = "GroupJoin"; $MessageObject->GroupName = $channel; + $MessageObject->Receiver = $this->userInfo[array_flip($this->channels)[$this->channels[$conn->resourceId]]]->user_name; $MessageObject->Username = $this->userInfo[$conn->resourceId]->user_name; $MessageObject->Fullname = $this->userInfo[$conn->resourceId]->first_name . " " . $this->userInfo[$conn->resourceId]->last_name; $MessageObject->Avatar = $this->userInfo[$conn->resourceId]->avatar; @@ -105,6 +109,7 @@ class ChatProcessor implements MessageComponentInterface $MessageObject = new \stdClass(); $MessageObject->ServerMessage = FALSE; $MessageObject->GroupName = $channel; + $MessageObject->Receiver = $this->userInfo[array_flip($this->channels)[$target]]->user_name; $MessageObject->Username = $this->userInfo[$conn->resourceId]->user_name; $MessageObject->Fullname = $this->userInfo[$conn->resourceId]->first_name . " " . $this->userInfo[$conn->resourceId]->last_name; $MessageObject->Avatar = $this->userInfo[$conn->resourceId]->avatar; @@ -136,6 +141,7 @@ class ChatProcessor implements MessageComponentInterface $MessageObject->ServerMessage = TRUE; $MessageObject->ServerMessageType = "TypingState"; $MessageObject->GroupName = $channel; + $MessageObject->Receiver = $this->userInfo[array_flip($this->channels)[$this->channels[$conn->resourceId]]]->user_name; $MessageObject->Username = $this->userInfo[$conn->resourceId]->user_name; $MessageObject->Fullname = $this->userInfo[$conn->resourceId]->first_name . " " . $this->userInfo[$conn->resourceId]->last_name; $MessageObject->Avatar = $this->userInfo[$conn->resourceId]->avatar; diff --git a/main/app/sprinkles/core/config/default.php b/main/app/sprinkles/core/config/default.php index 07fd2e6..60e3345 100644 --- a/main/app/sprinkles/core/config/default.php +++ b/main/app/sprinkles/core/config/default.php @@ -175,7 +175,7 @@ 'php' => [ 'timezone' => 'Europe/Berlin', 'error_reporting' => E_ALL, // Development - report all errors and suggestions - 'display_errors' => 'false', + 'display_errors' => 'true', 'log_errors' => 'true', // Let PHP itself render errors natively. Useful if a fatal error is raised in our custom shutdown handler. 'display_errors_native' => 'true' diff --git a/main/app/sprinkles/core/templates/pages/abstract/mainsite.html.twig b/main/app/sprinkles/core/templates/pages/abstract/mainsite.html.twig index 1821510..c27c071 100644 --- a/main/app/sprinkles/core/templates/pages/abstract/mainsite.html.twig +++ b/main/app/sprinkles/core/templates/pages/abstract/mainsite.html.twig @@ -8,7 +8,8 @@ <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> - <meta name="description" content="{% block page_description %}This page has not yet been configured.{% endblock %}"> + <meta name="description" + content="{% block page_description %}This page has not yet been configured.{% endblock %}"> <meta name="author" content="{% block page_author %}{{ site.author }}{% endblock %}"> <title>{{ site.title }} | {% block page_title %}New Page{% endblock %}</title> @@ -54,7 +55,7 @@ {# Canonical page link #} {% if block('page_canonical') %} - <link href="{{site.uri.base.scheme}}://{% block page_canonical %}{% endblock %}" rel="canonical" /> + <link href="{{ site.uri.base.scheme }}://{% block page_canonical %}{% endblock %}" rel="canonical" /> {% endif %} <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> @@ -85,7 +86,10 @@ {% block content_header %} <section class="content-header"> <h1>{% block header_title %}{{ block('page_title') }}{% endblock %}</h1> - {% if block('page_description') is not empty %}<h1><small>{% block header_description %}{{ block('page_description') }}{% endblock %}</small></h1>{% endif %} + {% if block('page_description') is not empty %} + <h1> + <small>{% block header_description %}{{ block('page_description') }}{% endblock %}</small> + </h1>{% endif %} {% block breadcrumb %} {% include 'navigation/breadcrumb.html.twig' with {page_title: block('page_title')} %} {% endblock %} @@ -116,7 +120,10 @@ {% endblock %} {% block scripts %} - <script>var current_user_id = {{ current_user.id }};</script> + <script> + var current_user_id = {{ current_user.id }}; + var current_username = "{{ current_user.user_name }}"; + </script> {# Override this block in a child layout template or page template to override site-level scripts. #} {% block scripts_site %} {{ assets.js('js/main') | raw }} diff --git a/main/app/sprinkles/core/templates/pages/index.html.twig b/main/app/sprinkles/core/templates/pages/index.html.twig index ab6b692..ca38372 100644 --- a/main/app/sprinkles/core/templates/pages/index.html.twig +++ b/main/app/sprinkles/core/templates/pages/index.html.twig @@ -23,7 +23,7 @@ </div> <div class="MainInTab FeedTabWindow"> {% for FeedImage in FeedImages %} - <img class="FeedImage" src="{{ site.uri.public }}/image/{{ FeedImage.PostID }}" alt="An image"> + <img class="FeedImage" src="{{ site.uri.public }}/image/{{ FeedImage.PostID }}" alt="You probably don't have an permission to see this image."> <br> {% endfor %} </div> @@ -89,7 +89,7 @@ <div class="MainInTab FriendsTabWindow"> <div class="FriendList"> {% for friend in friends %} - <img class="Avatar" data-src="{{ friend.avatar }}" data-caching-key="{{ friend.user_name }}_avatar_cached"> + <img class="Avatar" src="{{ friend.avatar }}" data-caching-key="{{ friend.user_name }}_avatar_cached"> <a class="FriendName" href="{{ site.uri.public }}/users/u/{{ friend.user_name }}">{{ friend.first_name }} {{ friend.last_name }}</a> <br> @@ -111,7 +111,7 @@ <div class="MainInTab PersonalTabWindow"> <div class="PersonalOverviewHeader"> <div class="GenderFab Female">♀</div> - <img class="Avatar" data-src="{{ current_user.avatar }}" data-caching-key="{{ current_user.user_name }}_avatar_cached" /> + <img class="Avatar" src="{{ current_user.avatar }}" data-caching-key="{{ current_user.user_name }}_avatar_cached" /> <div class="GenderFab Male">♂</div> </div> <br> @@ -128,19 +128,19 @@ <div class="Navbar"> <span id="0" class="NavbarIconWrap"> - <img data-src="{{ assets.url('assets://SiteAssets/icons/FriendFeedOutline.svg') }}" data-caching-key="FriendFeedOutline_nav_cached"> + <img src="{{ assets.url('assets://SiteAssets/icons/FriendFeedOutline.svg') }}" data-caching-key="FriendFeedOutline_nav_cached"> </span> <span id="1" class="NavbarIconWrap"> - <img data-src="{{ assets.url('assets://SiteAssets/icons/ExploreGlobeOutline.svg') }}" data-caching-key="ExploreGlobeOutline_nav_cached"> + <img src="{{ assets.url('assets://SiteAssets/icons/ExploreGlobeOutline.svg') }}" data-caching-key="ExploreGlobeOutline_nav_cached"> </span> <span id="2" class="NavbarIconWrap ActiveTab"> - <img data-src="{{ assets.url('assets://SiteAssets/icons/MessageBubbleOutlineActivated.svg') }}" data-caching-key="MessageBubbleOutlineActivated_nav_cached"> + <img src="{{ assets.url('assets://SiteAssets/icons/MessageBubbleOutlineActivated.svg') }}" data-caching-key="MessageBubbleOutlineActivated_nav_cached"> </span> <span id="3" class="NavbarIconWrap"> - <img data-src="{{ assets.url('assets://SiteAssets/icons/UserGroupOutline.svg') }}" data-caching-key="UserGroupOutline_nav_cached"> + <img src="{{ assets.url('assets://SiteAssets/icons/UserGroupOutline.svg') }}" data-caching-key="UserGroupOutline_nav_cached"> </span> <span id="4" class="NavbarIconWrap"> - <img data-src="{{ assets.url('assets://SiteAssets/icons/UserOutline.svg') }}" data-caching-key="UserOutline_nav_cached"> + <img src="{{ assets.url('assets://SiteAssets/icons/UserOutline.svg') }}" data-caching-key="UserOutline_nav_cached"> </span> </div> <span class='NavbarLine'></span> diff --git a/main/app/sprinkles/core/templates/pages/test.html.twig b/main/app/sprinkles/core/templates/pages/test.html.twig index 796ee72..6f64962 100644 --- a/main/app/sprinkles/core/templates/pages/test.html.twig +++ b/main/app/sprinkles/core/templates/pages/test.html.twig @@ -5,4 +5,33 @@ <input formenctype="multipart/form-data" type="file" name="image"/> </p> <input formenctype="multipart/form-data" type="submit"/> -</form>
\ No newline at end of file +</form> + +<form method="post" action="{{ site.uri.public }}/api/users/u/marvinborner/publickey"> + {% include "forms/csrf.html.twig" %} + <p> + <input type="text" name="PublicKey"/> + </p> + <input type="submit"/> +</form> + +<script> + var current_user_id = {{ current_user.id }}; + {% include "pages/partials/config.js.twig" %} +</script> + +{{ assets.js('js/main') | raw }} +<script src="{{ assets.url('assets://SiteAssets/js/encryption.js') }}"></script> + + +<script> + $.ajax({ + type: 'GET', + url: site.uri.public + '/api/users/u/' + 'marvinborner' + '/publickey', + dataType : "json", + success: function (response) { + console.log(response); + //window.location.reload(); + } + }); +</script>
\ No newline at end of file |