GithubHelp home page GithubHelp logo

darkwire / darkwire.io Goto Github PK

View Code? Open in Web Editor NEW
871.0 20.0 141.0 28.71 MB

End-to-end encrypted instant web chat

Home Page: https://darkwire.io

License: MIT License

Shell 0.48% JavaScript 94.31% HTML 0.33% CSS 0.21% Dockerfile 0.45% SCSS 0.22% Sass 3.00% TypeScript 0.98%
encryption chat anonymous-users socket-io privacy chatroom chat-room end-to-end-encryption chat-application cryptography

darkwire.io's Introduction

Darkwire.io

Simple encrypted web chat. Powered by socket.io, the web cryptography API. This project is an example of how client side encryption works and how you can integrate it as a chat service.

Deploy

Darkwire Server

Darkwire server is a Node.js application.

Darkwire Web Client

The Darkwire.io web client is written in JavaScript with React JS and Redux.

Development

Prerequisites

Copy .env.dist files in server/ and client/ directories without the .dist extensions and adapt them to your needs.

You must have a https connection for Darkwire to work because it's using crypto browser API which is accessible only on localhost and behind a https connection.

Manual setup

You can use nvm to install the right version of node using this command:

nvm install # If the right node version is not already installed
nvm use
npm install yarn -g # To install yarn

Install dependencies

$ yarn

Start server and client

$ yarn setup
$ yarn dev

Using docker-compose

Just run the following:

$ docker-compose up

This will automatically create the default .env files for you.

Production

Create server and client production builds

$ yarn build

Start server

$ yarn start

Using Docker

Build it.

$ docker build --tag darkwire.io:latest .

Then run it. Example:

$ docker run --init --name darkwire.io --rm -p 3001:3001 darkwire.io

You are able to use any of the environment variables available in server/.env.dist and client/.env.dist. The defaults are available in Dockerfile

Security

Please report any security issues to [email protected].

How it works

Darkwire uses a combination of asymmetric encryption (RSA-OAEP), symmetric session keys (AES-CBC) and signing keys (HMAC) for security.

Here's an overview of a chat between Alice and Bob (also applies to group chats):

  1. Bob creates a room and immediately creates a public/private key pair (RSA-OAEP).
  2. Alice joins the room and also creates a public/private key pair. She is sent Bob's public key and she sends Bob her public key.
  3. When Bob goes to send a message, three things are created: a session key (AES-CBC), a signing key (HMAC SHA-256) and an initialization vector (used in the encryption process).
  4. Bob's message is encrypted with the session key and initialization vector, and a signature is created using the signing key.
  5. The session key and signing key are encrypted with each recipient's public key (in this case only Alice, but in a group chat multiple).
  6. The encrypted message, initialization vector, signature, encrypted session key and encrypted signing key are sent to all recipients (in this case just Alice) as a package.
  7. Alice receives the package and decrypts the session key and signing key using her private key. She decrypts the message with the decrypted session key and vector, and verifies the signature with the decrypted signing key.

Group chats work the same way because in step 5 we encrypt keys with everyone's public key. When a message is sent out, it includes encrypted keys for everyone in the room, and the recipients then pick out the ones for them based on their user ID.

Darkwire does not provide any guarantee that the person you're communicating with is who you think they are. Authentication functionality may be incorporated in future versions.

File Transfer

Darkwire encodes documents into base64 using btoa and is encrypted the same way chat messages are.

  1. When a file is "uploaded", the document is encoded on the client and the server recieves the encrypted base64 string.
  2. The server sends the encrypted base64 string to clients in the same chat room.
  3. Clients recieving the encrypted base64 string then decrypts and decodes the base64 string using atob.

The default transferable file size limit is 4MB, but can be changed in .env file with the REACT_APP_MAX_FILE_SIZE variable.

Sockets & Server

Darkwire uses socket.io to transmit encrypted information using secure WebSockets (WSS).

Rooms are stored in memory on the server until all participants have left, at which point the room is destroyed. Only public keys are stored in server memory for the duration of the room's life.

Chat history is stored in each participant's browser, so it is effectively erased (for that user) when their window is closed.

darkwire.io's People

Contributors

alanfriedman avatar dependabot[bot] avatar dietmarw avatar emillen avatar geoder101 avatar goofy-mdn avatar jinxx0 avatar jrmi avatar mejans avatar quenty31 avatar seripap avatar tux-tn avatar vonkavalier avatar yabobjonez avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

darkwire.io's Issues

About anonymousity

Please make it so you mask people's IP's so the IPs doesnt show to anyone no matter what,completely anonymous and encrypted (that means no logs whatsoever no matter what,no trace of IPs or of any kind,nothing is saved on the server,people can't see people's IPs or any info. people won't use the chat otherwise.
Second thing..
About the roomname that changes everytime you enter. please make it so people can name their room with their own roomname instead of just name that comes up randomly

failed to install

The steps I follow seem like not installing any products related to darkwire chat system. Please advise on this matter.

Get latest version of NodeJS for ES2015 support

npm install -g n
n stable
npm install

Starting dev environment

npm run dev

Running tests locally

brew install chromedriver
npm test

Start a local instance of darkwire

npm run bundle
npm start

Changing ports, default is 3000

port=3000 npm start

dockerize it

Hello, I think what's missing from this fantastic project is support for docker, so as to be able to deploy the app anywhere and seamlessly.

For instance we should be able to:

1) Build the image

docker build -t darkwire .

2) Optionally push it to our private registry

docker tag darkwire private-registry/darkwire
docker push private-registry/darkwire

3) And ultimately run the app (in the production host)

docker run -d -p 3000:3000 private-registry/darkwire

I can send you a PR for a respective Dockerfile :)
What do you think?

[Security] XSS attack through user renaming

In Darkwire there is a feature where a user can rename himself from the originally assigned random alias to any username he'd like provided it is smaller than 16 characters:

https://github.com/seripap/darkwire.io/blob/master/src/room.js#L90

On the other hand, this length check is not done when the user initially connects to the room which is an issue because the username is generated by the client and not the server:

https://github.com/seripap/darkwire.io/blob/master/src/room.js#L40

Proof of concept:

const io = require('socket.io-client');
const socket = io.connect('http://127.0.0.1:3000/$ROOM_ID');

socket.emit('add user', {
  username: '<script>alert(1)</script>',
  publicKey: ''
});

setTimeout(() => socket.disconnect(), 3000);

Just replace the "$ROOM_ID" placeholder with the room id of a Darkwire room you are currently connected to in your browser and run the script.

Although this attack requires the room id, it still compromises any end user that opens a chat with the attacker. From the other security vulnerability issue #46 I opened we can see that it is possible for the app to leak the room id information so relying to much on this single line of defense might not be enough.

To fix this issue, the server has to validate that usernames are only alphanumeric and in a certain length range.

enhancement: support `/me` switch

Here another nice function from IRC. Using the /me switch one can express things like

/me really would like this feature

as

@dietmarw* really would like this feature

Not important but nice to have.

Download file is broken

When you send a file, the download link is broken. It's open a new tabs and do nothing else.

Critical security vulnerabilities

I'm not an expert on JS but it is the case of every programming language, that Math.random() is not a cryptographically secure pseudorandom number generator (CSPRNG).

Your encryption key generator is completely insecure.

Once that's fixed, the charset you're using is missing the 'm' and the length is only 16 chars. The current encryption keys have theoretical maximum strength of 61^16 = 94 bits. This is not enough; While it's secure against many crackers, it's not secure against nation states that break crypto. Ensure that the length of key generated by a CSPRNG is at least 43.

url base path

Hi, is it possible to edit the urlbase path for reverse proxy using a path like /darkwire? Thanks

Internationalization

Hi Darkwire users,

We are planning to internationalize all content to support our non-English speaking users. Please vote below for the language you'd most like to see translated first, or list a different language in the comments. We'll use this to help prioritize translation.









Sanitize text messages

Currently text messages seemed to be interpreted which makes it hard to use it for exchange of code snippets (especially HTML).

Example: "As you can see in the <script> tag..." becomes "As you can see in the tag...".
So textinput should be transmitted literal unless one of the official switches are used (e.g., /nick). This also means than one would loose HTML entity rendering but that is just as well. Especially when developers trying to discuss code.

"File Type not supported" unexpected message

Hi,

Thank you for this really great tool I've discovered recently ! I tried to send a file inside a chat, and I couldn't because of the message "File type not supported". I don't understand, and I don't find any information bout the file types supported.

Is it possible to know which files types are supported ? Why is there a restriction in the file type for sending files ? In my case, the file type was a .kdbx (file type for KeepassXC application), and it was under the size limit of 1Mb (my file is 60Kb).

Feature/Proposal: Encrypted Ephemeral File Storage (EEFS)

Proposal for Encrypted Ephemeral File Storage (EEFS)

Purpose: Provide a sharable link that allows temporary file download and/or image viewing.

Specs

  1. On file upload, assign a unique UUID to the file.
  2. On command, /pin <UUID> <file-key> <{options}> the file will be pinned to the top of the chatroom. This command will also temporarily store the file for up to 24 hours (default), via memory
  3. After pinning, the file will be available through a public URL: darkwire.io/<room-id>/<uuid>?key=file-key (if a key is not provided, the user will be redirected to the room-id)
  4. After 24 hours (default), the file will be removed from memory.
  5. If options is provided, it will change the behavior of the file pinning

Options

  • d (duration, optional): anywhere between 1m - 24hr. Will use shorthand annotation and support minutes and hours only ( m|h, ex:1m / 2m / 24h)

Other notes

  1. File upload handling will change when the file is pinned.
  • If the file has been pinned, it will be re-uploaded with the file-key as its encryption key.
  • Users who are currently in the chatroom will automatically receive the file-key while new users will be required to enter the file-key in order to access the file.
  1. A pinned file cannot be unpinned- only after the set duration of file expiration has passed.

  2. File keys cannot be changed and must have a minimum character count of 12

Target release: v2.1

Configuration

Hi !
Thanks for the work, our association has pull it on web and it's smoking good !

I need to know if there is a configuration file somewhere ?
Specially to set the default language for example or change the theme...

Add optionnal desktop notifications

When we get a new message and the windows is not focused, we should get an desktop notification id addition/in place of sound the notification.

If we click on the notification, the window/tab with notification is focused.

Should be activable/deactivable through parameters menu.

Server yarn test broken on fresh install

After a fresh install, if we try to execute the server side tests, we get this error:

yarn run v1.22.4
$ jest
 FAIL  src/utils/utils.test.js
  ● Test suite failed to run

    Requires Babel "^7.0.0-0", but was loaded with "6.26.3". If you are sure you have a compatible version of @babel/core, it is likely that something in your build process is loading the wrong version. Inspect the stack trace of this error to look for the first entry that doesn't mention "@babel/core" or "babel-core" to see what is calling Babel.
      
      at throwVersionError (node_modules/@babel/helper-plugin-utils/lib/index.js:65:11)
      at Object.assertVersion (node_modules/@babel/helper-plugin-utils/lib/index.js:13:11)
      at node_modules/@babel/plugin-transform-async-to-generator/lib/index.js:51:7
      at node_modules/@babel/helper-plugin-utils/lib/index.js:19:12
      at Function.memoisePluginContainer (node_modules/babel-core/lib/transformation/file/options/option-manager.js:113:13)
      at Function.normalisePlugin (node_modules/babel-core/lib/transformation/file/options/option-manager.js:146:32)
      at node_modules/babel-core/lib/transformation/file/options/option-manager.js:184:30
          at Array.map (<anonymous>)
      at Function.normalisePlugins (node_modules/babel-core/lib/transformation/file/options/option-manager.js:158:20)
      at OptionManager.mergeOptions (node_modules/babel-core/lib/transformation/file/options/option-manager.js:234:36)
      at OptionManager.init (node_modules/babel-core/lib/transformation/file/options/option-manager.js:368:12)
      at File.initOptions (node_modules/babel-core/lib/transformation/file/index.js:212:65)
      at new File (node_modules/babel-core/lib/transformation/file/index.js:135:24)
      at Pipeline.transform (node_modules/babel-core/lib/transformation/pipeline.js:46:16)
          at Generator.next (<anonymous>)
          at new Promise (<anonymous>)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        1.473s
Ran all test suites.
error Command failed with exit code 1.

v2.0 BETA

Core

  • Integrate React/Redux
  • Upgrade to Socket.io v2
  • Better testing framework (Jest)
  • UI/UX Updates
  • Remove all DOM manipulations
  • Better encryption method
    • Currently, encryption only happens on the message itself. v2.0 will be a rewrite of how encryption works- it should encrypt usernames whether they were randomly generated or set by the user
  • Check if client is connected to socket, reinitiate socket connection if not (partially completed)
  • Key based username system

Functionality

  • Setting: Ability to save settings (will require key-based username system)
  • Image embed on file owner when sent

Feature request: reuse room hashes

Current (designed) behaviour is that when the last person leaves a room the room "object" is destroyed. Visiting the a room address of a non existing room triggers the generation of a new random hashed room. Now it would be nice to be able to reuse earlier room "hashes" in order to establish a semi-secret meeting place that people can visit. Which means if a room object with a hasg is called that does not exist it should simply create the room with exactly that hash and not trigger the creation of a room with a new hash.
Was that understandable and would that be doable?

LetsEncrypt Broken

SSL Certs are broken right now. We are working on migrating the servers soon.

Message persistence on demand

I don't want to get into a war between Whatsapp vs. Signal vs. Telegram vs. Slack vs... but who gets all their contacts on the same tool? I don't want to create an account on all these platforms to be able to communicate with everyone. And what if I want to create a temporary group with customers for example. Do they all have to create an account on a common tool for a few months?

To my knowledge, there is no chatroom yet that

  • does not require an account or phone number,
  • which is easily shared via a link,
  • whose messages are e2e encrypted,
  • which displays desktop notifications,
  • which is open source and may be installed on multiple servers,
  • which allows you to retrieve messages that were sent while he was away because I'm not always in front of my computer when one of my contacts wants to talk to me.

With such a solution, I no longer need to make a choice. Not to mention the fact that I have to install a utility or that uses the phone number or the email. Yes I know my issue looks like that but eh, we are developers ;-)

In order for Darkwire to answer all these points, the last point is mainly missing, i.e. the possibility to receive the messages that were sent during my absence. I don't want to keep an ad vitam history of the messages, but just the last messages I didn't receive (within a month for example).
The idea is not to put an end to the ephemeral aspect of this chat but to complete it with a slightly longer term use. As long as you use it regularly, it stays alive. Messages are erased as they get older and if nobody uses the room for a while, it is totally deleted. This would be an option to be activated by the owner of the room if needed.

To meet this need I propose 3 technical solutions:

Option 1

The first idea is to use symmetrical AES-type encryption to encrypt messages. When you choose to enable persistence, a hash is added to the URL containing a passphrase to encrypt and decrypt messages. Each time a message is sent, it is stored encrypted in the store on the backend side and the messages are all sent back to each user who logs in. Only users with the correct hash in the url will be able to decrypt the messages.

Pros

  • Simple to implement
  • You have the URL, you have the history that goes with it.

Cons

  • The security of symmetrical encryption is significantly lower than asymmetrical encryption. The user should be warned that when he makes this choice, he decreases his security level compared to symmetrical encryption.

Option 2

With this option, the server keeps a list of users who logged in with their public key. When someone logs in, they receive a list of all users, even those who are not logged in anymore for this room. Each message are sent to the server encrypted with the public key of each recipients, like now, but messages whose recipient is not logged in are kept on the server until the user concerned logs in or until the message expires.

Pros

  • Maintains the same level of security
  • Easier to implement

Cons

  • Risk of keeping a lot of unnecessary messages if some users were only present at one time.
  • The history cannot be retrieved before a user's first connection since messages were not transmitted to him. We can imagine a fallback based on the re-transmission of the owner's messages in this case.

Option 3

This time, the first user in a room creates two encryption key pairs at the first connection. One for him as usual and one for messages. Then, for each user who logs in, the room owner sends the key messages encrypted with the user's public key (like a normal message in fact). The difference is that each time a message is sent, it is encrypted with the public key of the message and is sent only once. The message history is therefore kept only once on the server side and the encryption method remains asymmetrical. We can even imagine that is the default way of exchanging messages.

Pros

  • Same level of security as today (maybe even better? because the same message is encrypted only once which could limit statistical attacks from a compromised server? I don't know).
  • No extra storage cost depending on the number of users

Cons

  • Intermediate complexity
  • It is mandatory that a user with the message key must be present so that a new person can connect, but we can imagine to put this new user on hold while waiting for an owner with the message key.

What do you think? Did I miss an option?

Links are not clickable !

Hi. Since the new version, it's impossible to click directly into the links. Hope it's only a little bug.

Exit code 1 returned after yarn dev

This is what was returned after running "yarn dev":

$ concurrently 'cd client && yarn start' 'cd server && yarn dev'
[0] ''cd' is not recognized as an internal or external command,
[0] operable program or batch file.
[1] 'client' is not recognized as an internal or external command,
[1] operable program or batch file.
[0] 'cd exited with code 1
[1] client exited with code 1
error Command failed with exit code 1.

Add prettier to handle code style

To better code style consistency I propose to add prettier. This can be done in 4 PRs:

  1. Add prettierrc file and fix style for all server files
  2. Fix style for all frontend files
  3. Add commit hook to enforce style
  4. Add CI job to validate style (After/with #131)

[Security] Missing rel=noreferrer and rel=noopener in links

When a user sends a message containing a URL, Darkwire transforms the URL into an HTML anchor tag with an href link to the URL in question using the Autolinker module.

This creates two important security vulnerabilities.

  • Missing rel=noreferrer

When a user clicks on a link sent by another user in the same chat room, the request made by the browser to fetch the resource referenced by the URL will contain a Referrer header who's value will be the chatroom's full URL.

This creates an issue where any website administrator to which a Darkwire user browsed to can just look up the Darkwire chatroom URL in the Referrer header of his server logs.

  • Missing rel=noopener

Since anchor tags create by Autolinker contain a target=_blank attribute, users clicking on this link will be vulnerable to tab-jacking attacks.

More details can be found in this blog post: https://mathiasbynens.github.io/rel-noopener/

expired certificate

Looks like https://darkwire.io has an expired certificate:

screen shot 2017-04-03 at 16 36 46

Looks like you use letsencrypt with nginx, so an nginx reload might be enough to fix it if the certificate renewal happened without errors.

Persist some configuration data

It's annoying to set is nickname each time we connect, same for notification sound, etc.

It would be nice if this data could be stored in the localstorage for instance.

read upper-case `PORT` environment variable

To the best of my knowledge environment variable names are, by convention, in upper-case.
In addition, in some environments, such as in Heroku (the popular PaaS), the aforementioned convention is followed.

I believe it would be better if this convention is followed.
The issue that arises though, should such a change be adopted, whether it is backward-compatible or not.

I suggest that it is backward-compatible.
Namely, this change would suffice:

diff --git a/src/app.js b/src/app.js
index 7d3193d..cbfeffc 100644
--- a/src/app.js
+++ b/src/app.js
@@ -11,7 +11,7 @@ import fs from 'fs';
 import Room from './room';

 const $CONFIG = {
-  port: process.env.port || 3000
+  port: process.env.port || process.env.PORT || 3000
 };

 const app = express();

Do you have any other considerations?

PS: I have a PR ready, but I thought it would be better if I opened an issue first.

enhancement: make the "... is typing" message optional or improve

The ... is typing message is kind of a nuisance when the screen is full which means each time it appears all the conversation text jumps slightly up and then slightly down again. This is distracting. So it would be nice to either make it configurable so it can be switched off or change the message display in such a way that there is always space for a last blank line left in which the ... is typing message can appear without moving previous text.

Roadmap - v1.5

  • Encrypted File Transfer
  • Tests
  • Custom Handles/Slash commands
  • Option to hide " ... is typing " on either clients*
  • Support for Symbols + Emojis
  • Remove Vendor Files*

*Removed from v1.5

Button to download

Hi.
It was easier to write when the button to download was at the right instead of left.
When we want to write, we click on the button by accident and it opens the download windows.
Please can you replace it at the extrem right ?

Heroku deployment

I tried deploying darkwire.io on Heroku but it seems the gulp setup is conflicting. I don't know if you haver tried it with Heroku but given that you can one instance of a node.js application for free it makes a great test system for the newest features if one doesn't just want to test locally.

If there is interest in making it runnable on Heroku I can provide some logs. I was hoping to be able to fix it myself and send you a PR. But it seems my node.js foo is just too pathetic for that.

Client does not notice when server is no longer responding

We experienced that it happens from time to time that the server is "loosing" the room but the client still thinks it's connected and sends off message after message and even shows the other participants still present. Unfortunately I'm not sure how to best reproduce this properly.

Feature request: timestamps

It would be nice to have time stamps in front of the username or as mouse-over of the username. Whatever works best.

Feature request: custom handles

I've just started playing with this service (due to cryptocat becoming more and more unreliable due to outages) and one thing that would be nice to have is being able to rename the handles to make identification of different people easier. I know it will undermine the anonymity somewhat and you don't have any guarantee that the person is really the one it's saying it is but still would be nice to have.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.