Compare commits

..

No commits in common. "master" and "1.2.2" have entirely different histories.

18 changed files with 4025 additions and 3758 deletions

1
.github/FUNDING.yml vendored
View file

@ -1,2 +1 @@
github: [hexagon]
ko_fi: hexagon_56k

View file

@ -1,6 +0,0 @@
version: 2
updates:
- package-ecosystem: "npm" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"

View file

@ -27,4 +27,4 @@ jobs:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm run build:ci
- run: npm run build

View file

@ -1,6 +1,7 @@
FROM keymetrics/pm2:16-alpine
FROM node:16-alpine
COPY . /usr/src/app
WORKDIR /usr/src/app
RUN npm install --no-cache --production
RUN npm install --no-cache
EXPOSE 8080
CMD [ "pm2-runtime", "start", "pm2.json" ]
RUN chmod +x /usr/src/app/docker-entrypoint.sh
ENTRYPOINT ["/usr/src/app/docker-entrypoint.sh", "npm", "start"]

287
README.md
View file

@ -1,137 +1,150 @@
![cryptalk](https://i.imgur.com/1sH36n5.png)
![Node.js CI](https://github.com/Hexagon/cryptalk/workflows/Node.js%20CI/badge.svg?branch=master)
[![npm version](https://badge.fury.io/js/cryptalk.svg)](https://badge.fury.io/js/cryptalk)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.md)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/753ef40cec1747c2b5025f834635375b)](https://www.codacy.com/gh/Hexagon/cryptalk/dashboard?utm_source=github.com&utm_medium=referral&utm_content=Hexagon/cryptalk&utm_campaign=Badge_Grade)
# Cryptalk
Cyptalk is a HTML5/Node.js based, client side (E2EE) encrypted instant chat
## Features
* Client side AES-256-CBC encryption/decryption (the server is just a messenger)
* 256 bit key derived from your passphrase using PBKDF2
* Messages torched after a configurable delay, default is 600s.
* Simple setup using npm, Docker or Heroku
* Notification sounds (mutable)
* Native popup notifications
* Configurable page title
* Nicknames, optional.
* Quick-links using http://server/#Room:Passphrase, optional and insecure
## Installing
### Docker setup
To run latest cryptalk with docker, exposed on host port 80, simply run the following command to pull it from docker hub
```bash
sudo docker run -d --restart=always -p 80:8080 hexagon/cryptalk
```
### Heroku setup
Click the button below
[![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy?template=https://github.com/hexagon/cryptalk)
### Docker setup without using docker hub
Clone this repo, enter the new directory.
Build image
```bash
docker build . --tag="hexagon/cryptalk"
```
Run container, enable start on boot, expose to port 80 at host
```bash
sudo docker run -d --restart=always -p 80:8080 hexagon/cryptalk
```
Browse to ```http://<ip-of-server>/```
Done!
### npm setup
Install node.js, exact procedure is dependant on platform and distribution.
Install the app from npm
```bash
npm install cryptalk -g
````
Then issue the following to start the app
```bash
cryptalk
```
Browse to ```http://localhost:8080```
Done!
## Usage
```
Available commands:
Client:
/key StrongPassphrase Sets encryption key
/nick NickName Sets an optional nick
/mute Audio on
/unmute Audio off
/clear Clear on-screen buffer
/help This
/title Set your local page title
/torch AfterSeconds Console messages are torched
after this amount of seconds
(default 600).
Room:
/join RoomId Join a room
/leave Leave the room
/count Count participants
Host:
/connect Connect to host
/disconnect Disconnect from host
You can select any of the five last commands/messages with up/down key.
Due to security reasons, /key command is not saved, and command
history is automatically cleared after one minute of inactivity.
It is highly recommended to use incognito mode while chatting,
to prevent browsers from keeping history or cache.
```
## Development
Install node.js (development require >=12.0), exact procedure is dependant on platform and distribution.
Clone this repo
```bash
git clone https://github.com/Hexagon/cryptalk.git
cd cryptalk
```
Pull dependencies from npm
```bash
npm install
```
Start server
```bash
npm run start
```
Browse to ```http://localhost:8080```
To work on the JavaScript, edit the code in ```client/source/```. To test the changes, first run ```npm run build``` to lint, build and minify the code. Then restart the server.
![cryptalk](/screenshot.png)
![Node.js CI](https://github.com/Hexagon/cryptalk/workflows/Node.js%20CI/badge.svg?branch=master)
[![npm version](https://badge.fury.io/js/cryptalk.svg)](https://badge.fury.io/js/cryptalk)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.md)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/753ef40cec1747c2b5025f834635375b)](https://www.codacy.com/gh/Hexagon/cryptalk/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=Hexagon/cryptalk&amp;utm_campaign=Badge_Grade)
Cyptalk is a HTML5/Node.js based, client side (E2EE) encrypted instant chat
Features
========
* Client side AES-256-CBC encryption/decryption (the server is just a messenger)
* 256 bit key derived from your passphrase using PBKDF2
* Messages torched after a configurable delay, default is 600s.
* Simple setup using npm, Docker or Heroku
* Notification sounds (mutable)
* Native popup notifications
* Configurable page title
* Nicknames, optional.
* Quick-links using http://server/#Room:Passphrase, optional and insecure
Docker setup
========
To run latest cryptalk with docker, exposed on host port 80, simply run the following command to pull it from docker hub
```bash
sudo docker run -d --restart=always -p 80:8080 hexagon/cryptalk
```
Heroku setup
========
Click the button below
[![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy?template=https://github.com/hexagon/cryptalk)
Docker setup without using docker hub
========
Clone this repo, enter the new directory.
Build image
```bash
docker build . --tag="hexagon/cryptalk"
```
Run container, enable start on boot, expose to port 80 at host
```bash
sudo docker run -d --restart=always -p 80:8080 hexagon/cryptalk
```
Browse to ```http://<ip-of-server>/```
Done!
npm setup
========
Install node.js, exact procedure is dependant on platform and distribution.
Install the app from npm
```bash
npm install cryptalk -g
````
Then issue the following to start the app
```bash
cryptalk
```
Browse to ```http://localhost:8080```
Done!
Developer setup
========
Install node.js (development require >=12.0), exact procedure is dependant on platform and distribution.
Clone this repo
```bash
git clone https://github.com/Hexagon/cryptalk.git
cd cryptalk
```
Pull dependencies from npm
```bash
npm install
```
Start server
```bash
npn run start
```
Browse to ```http://localhost:8080```
To work on the JavaScript, edit the code in ```client/source/```. To test the changes, first run ```npm run build``` to lint, build and minify the code. Then restart the server.
Usage
========
```
Available commands:
Client:
/key StrongPassphrase Sets encryption key
/nick NickName Sets an optional nick
/mute Audio on
/unmute Audio off
/clear Clear on-screen buffer
/help This
/title Set your local page title
/torch AfterSeconds Console messages are torched
after this amount of seconds
(default 600).
Room:
/join RoomId Join a room
/leave Leave the room
/count Count participants
Host:
/connect Connect to host
/disconnect Disconnect from host
You can select any of the five last commands/messages with up/down key.
Due to security reasons, /key command is not saved, and command
history is automatically cleared after one minute of inactivity.
It is highly recommended to use incognito mode while chatting,
to prevent browsers from keeping history or cache.
```

View file

@ -1,31 +1,32 @@
/*------------------------------------*\
GENERIC
\*------------------------------------*/
html {
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box; /* Firefox, other Gecko */
box-sizing: border-box; /* Opera/IE 8+ */
box-sizing: border-box; /* Opera/IE 8+ */
}
*,
*:before,
*:after {
*, *:before, *:after {
box-sizing: inherit;
font-family: monospace, 'Courier New';
font-size: 12px;
}
body,
html {
body, html {
min-height: 100%;
min-width: 600px;
background-color: #181a1d;
background-color: #181A1D;
overflow: hidden;
padding: 0px;
margin: 0px;
color: #00dd00;
margin:0px;
color: #00DD00;
}
.good { color: #99ff99; }
.good { color: #99FF99; }
.bad { color: #ff7777; }
.info { color: #99ffff; }
.info { color: #99FFFF; }
.neutral { color: #eeeeee; }
/*------------------------------------*\
@ -37,8 +38,8 @@ html {
bottom: 40px;
position: absolute;
list-style-type: none;
padding: 0;
margin: 0;
padding:0;
margin:0;
}
/* Messages */
@ -49,7 +50,7 @@ html {
}
#chat li .timestamp {
color: #a0a00a;
color: #A0A00A;
}
/* Message types */
@ -57,27 +58,24 @@ html {
#chat i {
font-style: normal;
}
#chat i.motd {
color: #99ff99;
display:inline-block;
line-height: 12px !important;
}
#chat i.motd { color: #99FF99; display:inline-block; line-height: 12px !important; }
#chat i.info { color: #999999; }
#chat i.server { color: #99ffff; }
#chat i.server { color: #99FFFF; }
#chat i.error { color: #ff7777; }
#chat i.message { color: #eeeeee; }
#chat i.nick { color: #99ff99; }
#chat i.nick { color: #99FF99; }
#chat i.fatal { color: #ff7777; }
/*------------------------------------*\
INPUT & LOADER
\*------------------------------------*/
#input_wrapper {
right: 0;
bottom: 0;
left: 0;
right:0;
bottom:0;
left:0;
position: absolute;
height: 30px;
height:30px;
}
#input,
@ -92,35 +90,26 @@ html {
padding: 5px 5px 5px 15px;
color: #ffffff;
background-color:#272a2e;
color: #FFFFFF;
background-color:#272A2E;
height:30px;
border-top: 2px solid #153315;
}
#input {
z-index: 1;
}
#loader {
z-index: 0;
line-height: 20px;
font-size: 14px;
font-weight: 100;
font-family: tahoma;
}
.loading #loader {
z-index: 2;
}
#input { z-index: 1; }
#loader { z-index: 0; line-height: 20px; font-size: 14px; font-weight: 100; font-family: tahoma;}
/*------------------------------------*\
SPINNER
\*------------------------------------*/
.loading #loader { z-index: 2; }
.loading #loader span {
margin-left:-2px;
-webkit-animation: rotation 1s infinite linear;
}
@-webkit-keyframes rotation {
from { -webkit-transform: rotate(0deg); }
to { -webkit-transform: rotate(359deg); }
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(359deg);}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -9,7 +9,8 @@ for(var k in proto) ElementArray.prototype[k] = proto[k];
// Create to actual dollar function
function Dollar (selector) {
let matches = new ElementArray();
var match,
matches = new ElementArray();
if (selector !== undefined) {
if (selector === document) {
@ -17,8 +18,7 @@ function Dollar (selector) {
} else if (selector === window) {
matches.push(window);
} else {
let match = document.querySelectorAll(selector);
if (match) {
if ((match = document.querySelectorAll(selector))) {
for( var i=0; i < match.length; i++) {
matches.push(match[i]);
}

View file

@ -57,9 +57,9 @@ export default function (mediator, settings, templates) {
// Make sure the nick meets the length requirements
if (payload.length > settings.nick.maxLen) {
return mediator.emit('console:error', $.template(templates.messages.nick_to_long, { nick_maxLen: settings.nick.maxLen } ));
return mediator('console:error', $.template(templates.messages.nick_to_long, { nick_maxLen: settings.nick.maxLen } ));
} else if (payload.length < settings.nick.minLen) {
return mediator.emit('console:error', $.template(templates.messages.nick_to_short, {nick_minLen: settings.nick.minLen } ));
return mediator('console:error', $.template(templates.messages.nick_to_short, {nick_minLen: settings.nick.minLen } ));
}
// Set nick

View file

@ -128,6 +128,20 @@ export default function(mediator,settings,templates, sounds) {
components.input[0].removeAttribute('disabled');
components.inputWrapper[0].className = '';
components.input.focus();
},
_require: function (filepath, done) {
commands.lockInput();
commands.post('info', 'Requiring ' + filepath + '...');
require([filepath], function () {
commands.post('info', 'Successfully required ' + filepath + '.');
commands.unlockInput();
done();
}, function (e) {
commands.post('error', 'An error occurred while trying to load "' + filepath + '":\n' + e);
commands.unlockInput();
done();
});
}
},
@ -142,8 +156,7 @@ export default function(mediator,settings,templates, sounds) {
// If the active element is not the input, focus on it and exit the function.
// Ignore this when ctrl and/or alt is pressed!
if (!e.ctrlKey && !e.altKey && components.input[0] !== $.activeElement()) {
components.input.focus();
return;
return components.input.focus();
}
// Return immediatly if the buffer is empty or if the hit key was not <enter>
@ -163,8 +176,7 @@ export default function(mediator,settings,templates, sounds) {
payload,
function(retvals, recipients) {
if(!recipients) {
commands.post('error', $.template(templates.messages.unrecognized_command, { commandName: command }));
return;
return commands.post('error', $.template(templates.messages.unrecognized_command, { commandName: command }));
} else {
commands.clearInput();
}
@ -205,11 +217,13 @@ export default function(mediator,settings,templates, sounds) {
// Connect events
for (var commandName in commands) {
if (commandName !== 'post') {
if (commandName !== '_require' && commandName !== 'post') {
mediator.on('console:' + commandName, commands[commandName]);
}
}
mediator.on('console:require', commands._require);
mediator.on('console:post', function (data) {
commands.post(data.type, data.data, data.nick);
});

View file

@ -1,34 +1,42 @@
export default {
title: 'Claytonia Chat',
ttl: 600000,
motd: '<pre>\n\n' +
' Welcome to Claytonia Chat \n' +
' Tip of the day: /help \n' +
' Public Room: /join Claytonia \n' +
' Public Key: /key Claytonia \n' +
' Everyone in the room must have the same key to decrypt messages. \n' +
'----------------------------------------------------------------------' +
'</pre>',
nick: {
maxLen: 20,
minLen: 2,
},
key: {
maxLen: 1024,
minLen: 8,
},
room: {
minLen: 1,
maxLen: 64
},
notifications: {
maxOnePerMs: 3000
}
};
export default {
title: 'Cryptalk - Online',
ttl: 600000,
motd: '<pre>\n\n' +
'▄████▄ ██▀███ ▓██ ██▓ ██▓███ ▄▄▄█████▓ ▄▄▄ ██▓ ██ ▄█▀ \n' +
'▒██▀ ▀█ ▓██ ▒ ██▒▒██ ██▒▓██░ ██▒▓ ██▒ ▓▒▒████▄ ▓██▒ ██▄█▒ \n' +
'▒▓█ ▄ ▓██ ░▄█ ▒ ▒██ ██░▓██░ ██▓▒▒ ▓██░ ▒░▒██ ▀█▄ ▒██░ ▓███▄░ \n' +
'▒▓▓▄ ▄██▒▒██▀▀█▄ ░ ▐██▓░▒██▄█▓▒ ▒░ ▓██▓ ░ ░██▄▄▄▄██ ▒██░ ▓██ █▄ \n' +
'▒ ▓███▀ ░░██▓ ▒██▒ ░ ██▒▓░▒██▒ ░ ░ ▒██▒ ░ ▓█ ▓██▒░██████▒▒██▒ █▄ \n' +
'░ ░▒ ▒ ░░ ▒▓ ░▒▓░ ██▒▒▒ ▒▓▒░ ░ ░ ▒ ░░ ▒▒ ▓▒█░░ ▒░▓ ░▒ ▒▒ ▓▒ \n' +
' ░ ▒ ░▒ ░ ▒░▓██ ░▒░ ░▒ ░ ░ ▒ ▒▒ ░░ ░ ▒ ░░ ░▒ ▒░ \n' +
'░ ░░ ░ ▒ ▒ ░░ ░░ ░ ░ ▒ ░ ░ ░ ░░ ░ \n' +
'░ ░ ░ ░ ░ ░ ░ ░ ░░ ░ \n' +
'░ ░ ░ \n' +
' https://github.com/hexagon/cryptalk \n' +
' \n' +
' Tip of the day: /help \n' +
'----------------------------------------------------------------------' +
'</pre>',
nick: {
maxLen: 20,
minLen: 2,
},
key: {
maxLen: 1024,
minLen: 8,
},
room: {
minLen: 1,
maxLen: 64
},
notifications: {
maxOnePerMs: 3000
}
};

View file

@ -1,17 +0,0 @@
[Unit]
Description=Cryptalk Node.js App
Documentation=https://github.com/Hexagon/cryptalk
After=network.target
[Service]
ExecStart=/usr/bin/npm run start
WorkingDirectory=/home/cryptochat/cryptalk
Restart=always
RestartSec=10
Environment=NODE_ENV=production
Environment=PATH=/usr/bin
User=cryptochat
Group=cryptochat
[Install]
WantedBy=multi-user.target

11
docker-entrypoint.sh Normal file
View file

@ -0,0 +1,11 @@
#!/bin/sh
set -e
# /usr/src/app/external-public kan be mounted as a volume on host to expose
# statics to be hosted by host nginx
if [ -d /usr/src/app/external-public ]; then
cp -R /usr/src/app/client/public/* /usr/src/app/external-public/
fi
exec "$@"

7223
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,18 +1,17 @@
{
"name": "cryptalk",
"version": "1.2.9",
"version": "1.2.2",
"description": "Encrypted HTML5/Node.JS instant chat",
"main": "server/server.js",
"preferGlobal": true,
"private": false,
"scripts": {
"test": "echo \"No tests written yet\" && exit 0",
"build": "npm update && npm outdated && npm run test:lint && npx rollup -c rollup.config.js && npm run build:minify && npm run build:cleanup",
"build:ci": "npm run test:lint && npx rollup -c rollup.config.js && npm run build:minify && npm run build:cleanup",
"build": "npm run test:lint && npx rollup -c rollup.config.js && npm run build:minify && npm run build:cleanup",
"build:minify": "uglifyjs client/public/js/cryptalk.js --source-map -o client/public/js/cryptalk.min.js",
"build:cleanup": "(rm client/public/js/cryptalk.js || del client\\public\\js\\cryptalk.js)",
"test:lint": "eslint ./client/source/**/*.js ./server/*.js",
"start": "node ./server/server.js"
"start": "node server/server.js"
},
"keywords": [
"cryptalk",
@ -39,7 +38,7 @@
},
"bin": "./server/server.js",
"dependencies": {
"serve": "^13.0.2",
"serve": "^12.0.1",
"socket.io": "^4.3.1"
},
"os": [

View file

@ -1,11 +0,0 @@
{
"name": "cryptalk",
"script": "server/server.js",
"instances": "1",
"env": {
"NODE_ENV": "development"
},
"env_production" : {
"NODE_ENV": "production"
}
}

View file

@ -2,13 +2,13 @@ import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
module.exports = {
input: 'client/source/cryptalk.js',
output: {
file: 'client/public/js/cryptalk.js',
format: 'iife'
},
plugins: [
nodeResolve(),
commonjs()
]
input: 'client/source/cryptalk.js',
output: {
file: 'client/public/js/cryptalk.js',
format: 'iife'
},
plugins: [
nodeResolve(),
commonjs()
]
};