Note
Although this project is usable in the ways described below, this is not complete and progress can be seen here as well as planned improvements for the future. Additionally, this project has been reported to not work on MS Edge, Brave, and Safari.
TinyChat works through the usage of PeerJS. When you open a TinyChat web page, a User ID will be shown in the top right bar. This User ID is how people can contact you, but this will change every time you refresh the page. TinyChat aims to give end-to-end encrypted communication through RSA-OAEP, Elliptic Curve Diffie-Hellman, and AES-CBC encryption. Each conversation will have a unique AES-256 key with that key being shared using your RSA public key to allow the peer to produce a key that only the sender knows prior to encryption and that only you can decrypt as it will be encrypted with your RSA public key.
Important
Although the messages themselves are encrypted, many other metadata items are not. Further explanation of how this is done can be seen here.
What the attacker cannot read:
- The message body
- The time the message was sent
- The message ID
- The message ID being replied to (should the message be a reply)
- The effect being applied to the message (confetti, spotlight, etc.)
- The message event type (message, delivery receipt, typing indicator, message edit, etc.)
What the attacker can read:
- The User ID that sent the message (Needed for Message Decryption)
- User IDs in the group (Needed for Message Decryption)
-
Sending Messages-
Backend-
Create Conversation Groups with Client ID -
Create Conversations -
Create Messages -
Send Messages -
Receive Messages
-
-
Frontend-
Create Conversation UI -
Create Message UI -
View Message History
-
-
-
Themes (Light/Dark)-
Frontend-
Light Theme -
Dark Theme
-
-
-
Delivery Receipts-
Backend-
Send Delivery Receipts -
Receive Delivery Receipts
-
-
Frontend-
Show Delivery Receipts in UI
-
-
-
Typing Indicators-
Backend-
Handle Typing Logic -
Send Typing Indication -
Receive Typing Indication
-
-
Frontend-
Show Typing Indicators in UI
-
-
-
Editing Messages-
Backend-
Send Edited Messages -
Receive Edited Messages
-
-
Frontend-
Edit Message UI -
Edited Message Indication in UI
-
-
-
End-To-End Encrypted-
Backend-
Establish RSA Keys-
Public -
Private
-
-
Share AES Key Encrypted with RSA -
Send Encrypted Messages
-
-
-
Replies-
Backend-
Create Replies -
Send Replies
-
-
Frontend-
Create Replies -
Reply Indication in UI
-
-
-
Unsend/Delete-
Backend-
Create Deletion Request -
Handle Deletion Request for Sender -
Handle Deletion Request for Receiver
-
-
Frontend-
Create Deletion Request -
Delete Message from Sender -
Delete Message from Receiver
-
-
-
Reactions-
Backend-
Create Reactions -
Send Reactions
-
-
Frontend-
Create Reactions -
Reaction Indication in UI
-
-
-
Files-
Backend-
Upload File -
Download File
-
-
Frontend-
Upload File -
Download File
-
-
- Effects
- Backend
- Create Effects
- Send Effects
- Frontend
- Create Effects
- Reaction Indication in UI
- Backend
Building this project for development purposes requires either npm
or tsc
to be installed. For testing the project, npm
must be installed specifically.
NPM Method:
-
Building: Run
npm run build
which will installtsc
locally and build the main website. After running the command once, the project can then be rebuilt withnpx tsc
which will compile the TypeScript files for usage. Alternatively,npm run build
can be used to rebuild the main website.tsc
can also be manually installed withnpm install -g typescript
to remove the need to usenpx
. -
Testing: Run
npm run test
which will installtsc
locally, build both the main website and the testing backend, and run the testing backend. Modifications to the main website can be recompiled withnpx tsc
and modifications to the testing backend can be recompiled withnpx tsc -p test.tsconfig.json
. Alternatively,npm run test
can be used to rebuild both the main website and testing backend.
TSC Method:
-
Building: If
tsc
has already been installed through eithernpm install -g typescript
or through other methods, compiling is as simple as runningtsc
to build the main website. The project can then be rebuilt withtsc
again. -
Testing: Testing cannot be done without
npm
installed.
After the project has been compiled, simply open TinyChat.html
with your desired web browser and chat away!
Note
Any changes to TypeScript Files during development will require rebuilding the project as used prior. Modifications to any other file types (i.e. HTML, CSS) will be automatically updated when reloading the page.
graph TB;
A["
Client
<hr>#8226; #peer: Peer
#8226; #editing: string
#8226; #replying: string
#8226; #reacting: string
#8226; #keyPair: CryptoKeyPair
#8226; #aesKeys: { [id: string]: [Uint8Array, CryptoKey] }
#8226; #dhKeys: { [id: string]: { [id: string]: CryptoKeyPair } }
#8226; #window: window
#8226; #crypto: Crypto
#8226; #eventID: string | HTMLInputElement | undefined
<hr>#8226; createChat: (to: string): HTMLSpanElement
#8226; #render: (to: string, messageData: MessageData): void
#8226; #send: (to: string, messageData: MessageData): void
#8226; react: (reaction: string): void
#8226; schedule: (seconds: number | undefined): void
#8226; openContext: (): void
#8226; openReacting: (): void
#8226; markReply: (): void
#8226; markEdit: (): void
#8226; unsend: (): void
"] --> |Has a| B["
Peer
#8226; id: string
#8226; connections: object
#8226; disconnected: boolean
#8226; destroyed: boolean
"];
C["
MessageData
<hr>#8226; from: string
#8226; body: string
#8226; time: string
#8226; id: string
#8226; event: MessageDataEvent
#8226; prev: string
#8226; effect: MessageDataEffects
"];
D["
MessageDataEvent
<hr>#8226; Typing
#8226; StopTyping
#8226; Edit
#8226; Unsend
#8226; Delivered
#8226; GroupRSAKeyRequest
#8226; GroupRSAKeyShare
#8226; RSAKeyShare
#8226; AESKeyShare
"];
E["
MessageDataEffects
<hr>
"];
graph TB
A["TinyChat.html"];
B["
PeerJS
<hr>#8226; https://unpkg.com/[email protected]/dist/peerjs.min.js
"] --> A;
C["TinyChat.js"] --> A;
D["
NPM
<hr>#8226; typescript
"] --> C;
E["
TinyChat.ts
<hr>#8226; MessageDataEvent
#8226; MessageDataEffects
#8226; MessageData
#8226; Client
"] --> D;
F["TinyChat.css"] --> A;
G["Testing.js"];
H["
NPM
<hr>#8226; typescript
#8226; @peculiar/webcrypto
#8226; @types/node
#8226; fs
#8226; jsdom
"] --> G;
C --> G;
I["
Testing.ts
<hr>#8226; createChatTest
#8226; renderTest
"] --> H;
graph TB;
subgraph "Client #1"
A>Creates an RSA Key] --> |This is done once each time the page is opened or refreshed| B>Generate New AES Key Request];
B --> |This is done for each client| D>Sends RSA Public Key];
J --> K>Decrypt Encrypted Diffie-Hellman Public Key with RSA Private Key];
K --> L>"Generate Diffie-Hellman Public/Private Key"];
B --> F>Generate AES Key];
F --> M;
L --> M>One-Time-Pad = Diffie-Hellman Symmetric Key ^ Generated AES Key];
M --> N>Encrypt Generated Diffie-Hellman Public Key and One-Time-Pad with Client #+'s RSA Public Key];
N --> O>Send Encrypted Data to Client #+];
end
subgraph "Client #+"
C>Creates an RSA Key] --> |This is done once each time the page is opened or refreshed| E>Creates a new Conversation];
D --> E>Waits for RSA Public Key];
E --> G>"Generate Diffie-Hellman Public/Private Key"];
G --> H>Encrypt Generated Diffie-Hellman Public Key with Client #1's RSA Public Key];
H --> I>Send Encrypted Data and RSA Public Key to Client #1];
I --> J>Receive Encrypted Data from Client #+];
O --> P>Receive Encrypted Data from Client #1];
P --> Q>Decrypt Encrypted Diffie-Hellman Public Key and One-Time-Pad with RSA Private Key];
Q --> R>AES Key = One-Time-Pad ^ Diffie-Hellman Symmetric Key];
end
classDef user fill:#fff,color:#000
class B user;
graph LR;
subgraph "Sender"
subgraph "Modifiers"
P>Edit] --> O;
Q>Reply] --> O;
end
O>XOR] --> A;
A>A Message is Typed];
A --> S>Stop Typing];
S --> T>A Stop Typing Indicator is Sent to each Receiver];
A --> B>A Typing Indicator is Sent to each Receiver];
A --> E>The Message is Sent];
E --> F>The Message is Encrypted with the AES Symmetric Key];
R>Reaction] --> F;
F --> G>The Encrypted Message is Sent to each Receiver];
E --> L>The Message is Added to the UI];
L --> M>The Sender Waits for a Delivery Receipt];
M --> |Only for First Received| N>A Delivery Receipt is Added to the UI];
end
subgraph "Receivers"
B --> C>A Typing Indicator is Received];
C --> D>The Typing Indicator is Added to the UI];
G --> H>The Encrypted Message is Received];
H --> I>The Encrypted Message is Decrypted with the AES Symmetric Key];
I --> J>The Decrypted Message is Added to the UI];
H --> K>A Delivery Receipt is Sent to the Sender];
K --> M;
T --> U>A Stop Typing Indicator is Received];
U --> V>The Typing Indicator is Removed from the UI];
end
classDef user fill:#fff,color:#000
class A,E,P,Q,R,S user;