implemented message post in ts + some optimizations
This commit is contained in:
parent
874683ad0c
commit
767d7d7b03
@ -4,5 +4,5 @@ export class ChatMessageDTO {
|
||||
public toUser: string | undefined;
|
||||
public fromUser: string | undefined;
|
||||
public messageCipher!: MessageCipherDTO;
|
||||
public messageTime!: Date;
|
||||
public messageTime: Date | undefined | null;
|
||||
}
|
@ -8,7 +8,6 @@ import { ModelFactory } from "./model/ModelFactory";
|
||||
import { ActiveUserViewModel } from "./viewmodel/ActiveUserViewModel";
|
||||
import { ChatMessageViewModel } from "./viewmodel/ChatMessageViewModel";
|
||||
import * as Handlebars from "handlebars";
|
||||
import markdownit = require('markdown-it');
|
||||
import { ChatModel } from "./model/ChatModel";
|
||||
import { ChatView } from "./view/ChatView";
|
||||
import { ChatController } from "./controller/ChatController";
|
||||
@ -18,8 +17,9 @@ import * as log from 'loglevel';
|
||||
// import log from 'loglevel';
|
||||
import { EncryptionService } from "./service/EncryptionService";
|
||||
import { SJCLEncryptionService } from "./service/SJCLEncryptionService";
|
||||
import { MessageCipherDTO } from "./dto/MessageCipherDTO";
|
||||
// var markdownit = require('markdown-it');
|
||||
var md = new markdownit();
|
||||
// var md = new markdownit();
|
||||
|
||||
|
||||
const userBox = document.getElementById('contacts-box');
|
||||
@ -72,8 +72,8 @@ var msgContainerTemplate = Handlebars.compile(source);
|
||||
JsonAPI.ACTIVE_USERS_GET + 'aef';
|
||||
|
||||
const encryptionService: EncryptionService = new SJCLEncryptionService();
|
||||
let ct = encryptionService.encrypt("password","data");
|
||||
console.log(encryptionService.decrypt("password", JSON.parse(ct as string)));
|
||||
let messageCipherDTO: MessageCipherDTO = encryptionService.encrypt("password","data");
|
||||
console.log(encryptionService.decrypt("password", messageCipherDTO));
|
||||
|
||||
Handlebars.registerHelper('avatar', function() {
|
||||
return '<div class="img_cont_msg"> <img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img_msg"> </div>';
|
||||
|
@ -39,7 +39,7 @@ export class ChatModel implements Subject {
|
||||
console.log('Subject: Detached an observer.');
|
||||
}
|
||||
|
||||
public setUserMessages(username: string, messages: ChatMessageViewModel[]) {
|
||||
private setUserMessages(username: string, messages: ChatMessageViewModel[]) {
|
||||
this._messagesMap.set(username, messages);
|
||||
}
|
||||
|
||||
@ -61,13 +61,15 @@ export class ChatModel implements Subject {
|
||||
this.notify("some user");
|
||||
}
|
||||
|
||||
public async getmessages(userName: string, passphrase: string, lastMessageTime: string | null): Promise<ChatMessageViewModel[]> {
|
||||
const cVMs = await ChatModelHelper.getMessages(userName, passphrase, lastMessageTime, this);
|
||||
public async getmessages(contactName: string, passphrase: string, lastMessageTime: string | null): Promise<ChatMessageViewModel[]> {
|
||||
const cVMs = await ChatModelHelper.getMessages(contactName, passphrase, lastMessageTime, this);
|
||||
if (cVMs != null) {
|
||||
log.info('Subject: My state has just changed')
|
||||
log.debug(cVMs);
|
||||
this._messagesMap.set(userName, cVMs);
|
||||
this.notify(userName);
|
||||
// this._messagesMap.set(userName, cVMs);
|
||||
this.setUserMessages(contactName, cVMs);
|
||||
JsonAPI.contactName = contactName;
|
||||
this.notify(contactName);
|
||||
}
|
||||
else {
|
||||
log.error('Messages were null');
|
||||
|
@ -12,7 +12,7 @@ import { EncryptionService } from "../service/EncryptionService";
|
||||
import { SJCLEncryptionService } from "../service/SJCLEncryptionService";
|
||||
import { ChatModel } from "./ChatModel"
|
||||
export class ChatModelHelper {
|
||||
private static readonly encryptionService = new SJCLEncryptionService();
|
||||
private static readonly _encryptionService: EncryptionService = new SJCLEncryptionService();
|
||||
|
||||
public static async getMessages(userName: string, passphrase: string, lastMessageTime: string | null, chatModel: ChatModel): Promise<ChatMessageViewModel[]> {
|
||||
switch (lastMessageTime) {
|
||||
@ -54,8 +54,9 @@ export class ChatModelHelper {
|
||||
const vm = new ChatMessageViewModel();
|
||||
vm.fromUser = chatMessageDTO.fromUser;
|
||||
vm.toUser = chatMessageDTO.toUser;
|
||||
vm.messageTime = chatMessageDTO.messageTime;
|
||||
vm.message = this.encryptionService.decrypt(passphrase, chatMessageDTO.messageCipher) as string;
|
||||
// vm.messageTime = chatMessageDTO.messageTime;
|
||||
chatMessageDTO.messageTime == null ? log.error("Message time somehow null") : vm.messageTime = chatMessageDTO.messageTime;
|
||||
vm.message = this._encryptionService.decrypt(passphrase, chatMessageDTO.messageCipher) as string;
|
||||
return vm;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { MessageCipherDTO } from "../dto/MessageCipherDTO";
|
||||
|
||||
export interface EncryptionService {
|
||||
encrypt(passphrase: string, plainText: string): Object,
|
||||
decrypt(passphrase: string, cipher: Object): Object
|
||||
encrypt(passphrase: string, plainText: string): any,
|
||||
decrypt(passphrase: string, cipher: MessageCipherDTO): string
|
||||
}
|
@ -1,14 +1,15 @@
|
||||
import { EncryptionService } from "./EncryptionService";
|
||||
import * as sjcl from "sjcl";
|
||||
import { MessageCipherDTO } from "../dto/MessageCipherDTO";
|
||||
|
||||
export class SJCLEncryptionService implements EncryptionService {
|
||||
private readonly params: any = { mode: "gcm", ts: 128, adata: "", iter: 10000}
|
||||
public encrypt(passphrase: string, plainText: string): Object {
|
||||
return sjcl.encrypt(passphrase, plainText, this.params);
|
||||
private readonly params = { mode: "gcm", ts: 128, adata: "", iter: 10000}
|
||||
public encrypt(passphrase: string, plainText: string): MessageCipherDTO {
|
||||
// @ts-ignore
|
||||
return JSON.parse(sjcl.encrypt(passphrase, plainText, this.params) as string) as MessageCipherDTO;
|
||||
}
|
||||
|
||||
public decrypt(passphrase: string, cipher: Object): Object {
|
||||
// return sjcl.decrypt(passphrase, cipher as sjcl.SjclCipherEncrypted, undefined, undefined);
|
||||
public decrypt(passphrase: string, cipher: MessageCipherDTO): string {
|
||||
return sjcl.decrypt(passphrase, JSON.stringify(cipher), undefined, undefined);
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
export namespace JsonAPI {
|
||||
// @ts-ignore: Cannot find name 'hostAddress'.
|
||||
export let userName: string | null = localStorage.getItem('userName');
|
||||
export let principleName: string | null = localStorage.getItem('username');
|
||||
export let contactName: string | null;
|
||||
export let authToken: string | null = localStorage.getItem('authToken');
|
||||
export const ACTIVE_USERS_GET = `/api/chat/get/active-users`;
|
||||
export const CHAT_MESSAGES_GET = `/api/chat/get/messages`;
|
||||
export const MESSAGE_POST = '/api/chat/post/message';
|
||||
|
||||
}
|
@ -7,35 +7,51 @@ import * as DOMPurify from 'dompurify';
|
||||
import { MarkDownService } from "../service/MarkDownService";
|
||||
import { MarkDownItMarkDownService } from "../service/MarkDownItMarkDownService";
|
||||
import { JsonAPI } from "../singleton/JsonAPI";
|
||||
import { MessageCipherDTO } from "../dto/MessageCipherDTO";
|
||||
import { SJCLEncryptionService } from "../service/SJCLEncryptionService";
|
||||
import { EncryptionService } from "../service/EncryptionService";
|
||||
import { ChatMessageDTO } from "../dto/ChatMessageDTO";
|
||||
import { fetchHandler } from "./FetchHandler";
|
||||
// var md = new markdownit();
|
||||
|
||||
export class ChatView implements Observer {
|
||||
private readonly _element: HTMLElement;
|
||||
private readonly _chatModel: ChatModel;
|
||||
private readonly _messageContainer: HTMLElement;
|
||||
// private readonly _messageSendButton: HTMLElement;
|
||||
private readonly _messageSendTemplate = TemplateFactory.getTemplate('msg_container_send_template');
|
||||
private readonly _messageReceiveTemplate = TemplateFactory.getTemplate('msg_container_template');
|
||||
private readonly _markdownService: MarkDownService = new MarkDownItMarkDownService();
|
||||
private readonly _encryptionService: EncryptionService = new SJCLEncryptionService();
|
||||
|
||||
|
||||
constructor(model: ChatModel, element: HTMLElement) {
|
||||
this._element = element;
|
||||
constructor(chatModel: ChatModel, messageContainer: HTMLElement) {
|
||||
this._messageContainer = messageContainer;
|
||||
this._chatModel = chatModel;
|
||||
// this._messageSendButton = messageSendButton;
|
||||
this.addEventListeners();
|
||||
}
|
||||
|
||||
|
||||
update(data: ChatMessageViewModel[]): void {
|
||||
log.info('ChatView: updating view');
|
||||
// let html: string = "";
|
||||
this._messageContainer.innerHTML = "";
|
||||
data.forEach((vm: ChatMessageViewModel) => {
|
||||
const vmTemp = vm;
|
||||
vmTemp.message = this._markdownService.render(vm.message);
|
||||
/** Very Important!!!
|
||||
* Sanitizing HTML before displaying on webpage to prevent XSS attacks!!
|
||||
*/
|
||||
if (vmTemp.fromUser == JsonAPI.userName) {
|
||||
$(this._element).append(DOMPurify.sanitize(this._messageSendTemplate(vmTemp)));
|
||||
let rendered;
|
||||
if (vmTemp.fromUser == JsonAPI.principleName) {
|
||||
rendered = DOMPurify.sanitize(this._messageSendTemplate(vmTemp));
|
||||
|
||||
}
|
||||
else {
|
||||
$(this._element).append(DOMPurify.sanitize(this._messageReceiveTemplate(vmTemp)));
|
||||
rendered = DOMPurify.sanitize(this._messageReceiveTemplate(vmTemp));
|
||||
}
|
||||
$(this._messageContainer).append(rendered);
|
||||
log.debug()
|
||||
// html += this._messageSendTemplate(vm);
|
||||
});
|
||||
|
||||
@ -43,4 +59,94 @@ export class ChatView implements Observer {
|
||||
// this._element.innerHTML = html;
|
||||
// log.debug(this._element.innerHTML);
|
||||
}
|
||||
|
||||
private addEventListeners(): void {
|
||||
this.addChatFormEL();
|
||||
}
|
||||
|
||||
private addChatFormEL() {
|
||||
const chatForm = document.getElementById('chatMessageForm') as HTMLSelectElement;
|
||||
|
||||
if (chatForm == null) {
|
||||
log.error("Chat form is null");
|
||||
}
|
||||
else {
|
||||
chatForm.addEventListener('submit', (e) => this.createChatMessageDTO(e, chatForm))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private createChatMessageDTO(e: Event, chatForm: HTMLSelectElement): void {
|
||||
e.preventDefault();
|
||||
|
||||
let contactName = JsonAPI.contactName;
|
||||
|
||||
if(contactName == null)
|
||||
{
|
||||
log.error("Contact name is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!chatForm.checkValidity()) {
|
||||
console.log("error");
|
||||
chatForm.classList.add('was-validated');
|
||||
return;
|
||||
}
|
||||
chatForm.classList.add('was-validated');
|
||||
|
||||
|
||||
const chatInput = document.getElementById('chatInput') as HTMLInputElement;
|
||||
const passphraseInput = document.getElementById('passphrase') as HTMLInputElement;
|
||||
|
||||
if (chatInput.value == '' || chatInput.value == null) {
|
||||
log.error("Chat input is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (passphraseInput.value == '' || passphraseInput.value == null) {
|
||||
log.error("Chat input is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const messageContent = chatInput.value;
|
||||
const context = { fromUser: JsonAPI.principleName, message: this._markdownService.render(messageContent), messageTime: new Date().toLocaleString() };
|
||||
const msgContainer: string = this._messageSendTemplate(context);
|
||||
$(this._messageContainer).append(DOMPurify.sanitize(msgContainer));
|
||||
// scrollChatAreaAnimated(2400);
|
||||
// let messageCipher = sjcl.encrypt(passphraseInput.value, messageContent, { mode: "gcm", ts: 128, adata: "", iter: iterations });
|
||||
let messageCipher: MessageCipherDTO = this._encryptionService.encrypt(passphraseInput.value, messageContent)
|
||||
// let messageCipherJson = JSON.parse(messageCipher);
|
||||
let chatMessageDTO = {
|
||||
"fromUser": JsonAPI.principleName,
|
||||
"toUser": contactName,
|
||||
"messageCipher": messageCipher,
|
||||
// "messageTime": null
|
||||
}
|
||||
// @ts-ignore
|
||||
this.sendMessageAJAX(chatMessageDTO);
|
||||
}
|
||||
|
||||
private sendMessageAJAX(chatMessageDTO: ChatMessageDTO): void {
|
||||
let headers = new Headers();
|
||||
// console.log("Token = " + btoa("hmm" + ":" + "hmm"))
|
||||
|
||||
// headers.append('Accept','application/json')
|
||||
headers.append('Content-Type', 'application/json');
|
||||
// headers.append('Authorization', basicAuthToken);
|
||||
// @ts-ignore
|
||||
headers.append('X-AUTH-TOKEN', JsonAPI.authToken);
|
||||
fetch(JsonAPI.MESSAGE_POST, {
|
||||
method: 'POST',
|
||||
headers: headers,
|
||||
body: JSON.stringify(chatMessageDTO)
|
||||
})
|
||||
.then(response => {
|
||||
log.debug(response);
|
||||
return response.clone();
|
||||
})
|
||||
.then(response => fetchHandler(response));
|
||||
|
||||
}
|
||||
}
|
33
chatto/src/main/javascript/ts/src/view/FetchHandler.ts
Normal file
33
chatto/src/main/javascript/ts/src/view/FetchHandler.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { sprintf } from "sprintf-js";
|
||||
|
||||
export function fetchHandler(response: any) {
|
||||
if (response.ok) {
|
||||
return response.json().then((json: any) => {
|
||||
// the status was ok and there is a json body
|
||||
// return Promise.resolve({ json: json, response: response });
|
||||
// alertify.success('Message sent succesfully' + sprintf(" (http code %d)", response.status));
|
||||
}).catch((err: any) => {
|
||||
// the status was ok but there is no json body
|
||||
// return Promise.resolve({ response: response });
|
||||
// alertify.success('Message sent succesfully' + sprintf(" (http code %d)", response.status));
|
||||
});
|
||||
|
||||
} else {
|
||||
return response.json().catch((err: any) => {
|
||||
// the status was not ok and there is no json body
|
||||
// throw new Error(response.statusText);
|
||||
// alertify.error('Some error occured. Please try again.');
|
||||
}).then((json: any) => {
|
||||
// the status was not ok but there is a json body
|
||||
// throw new Error(json.error.message); // example error message returned by a REST
|
||||
// let delay = alertify.get('notifier', 'delay');
|
||||
// alertify.set('notifier', 'delay', 30);
|
||||
let errorMessage = "";
|
||||
json.errors.forEach(function(data: any) {
|
||||
errorMessage += sprintf("Field Name: %s \n Rejected value: %s \n Reason: %s \n", data.field_name, data.rejected_value, data.error_message);
|
||||
});
|
||||
// alertify.error(sprintf('There were errors in your message - %s', errorMessage));
|
||||
// alertify.set('notifier', 'delay', delay);
|
||||
});
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -234,7 +234,7 @@
|
||||
</div>
|
||||
<div class="msg_container">
|
||||
{{{message}}}
|
||||
<span class="msg_time">{{time}}</span>
|
||||
<span class="msg_time">{{messageTime}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -243,7 +243,7 @@
|
||||
<div class="d-flex justify-content-end mb-4">
|
||||
<div class="msg_container_send">
|
||||
{{{message}}}
|
||||
<span class="msg_time_send">{{time}}</span>
|
||||
<span class="msg_time_send">{{messageTime}}</span>
|
||||
</div>
|
||||
<!-- <div class="img_cont_msg">
|
||||
<img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg"
|
||||
|
Loading…
Reference in New Issue
Block a user