Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
0bd49c092d | |||
ede41e5715 | |||
6c5bbc3f64 | |||
5ae61222f4 | |||
dce526922e | |||
8c8ede431c | |||
c4417cf802 | |||
0e1c17973b | |||
f2cfb6bda0 | |||
dda30bf5af | |||
5081f9dbf4 | |||
6b81cec83a | |||
40cab75f96 | |||
03a9df81ec | |||
3543ef2824 | |||
496c115fa9 | |||
dc9fde39be |
1736
Cargo.lock
generated
1736
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
40
Cargo.toml
40
Cargo.toml
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "aira"
|
||||
version = "0.0.3"
|
||||
version = "0.1.1"
|
||||
authors = ["Hardcore Sushi <hardcore.sushi@disroot.org>"]
|
||||
edition = "2018"
|
||||
exclude = ["src/frontend"]
|
||||
@ -9,37 +9,41 @@ exclude = ["src/frontend"]
|
||||
rand = "0.8"
|
||||
rand-7 = { package = "rand", version = "0.7.3" }
|
||||
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros", "net", "io-util"] }
|
||||
async-psec = { version = "0.3", features = ["split"] }
|
||||
async-psec = { version = "0.4", features = ["split"] }
|
||||
lazy_static = "1.4"
|
||||
socket2 = "0.4"
|
||||
rusqlite = { version = "0.25.1", features = ["bundled"] }
|
||||
ed25519-dalek = "1" #for singing
|
||||
sha2 = "0.9"
|
||||
rusqlite = { version = "0.27", features = ["bundled"] }
|
||||
ed25519-dalek = "1" #for singatures
|
||||
sha2 = "0.10"
|
||||
aes-gcm = "0.9"
|
||||
aes-gcm-siv = "0.10" #Database
|
||||
hkdf = "0.11"
|
||||
aes-gcm-siv = "0.10" #database encryption
|
||||
hkdf = "0.12"
|
||||
hex = "0.4"
|
||||
actix-web = "3"
|
||||
actix-multipart = "0.3"
|
||||
time = "0.2" #needed for actix cookies
|
||||
actix-web = "4"
|
||||
env_logger = "0.9"
|
||||
actix-multipart = "0.4"
|
||||
time = "0.3" #needed for actix cookies
|
||||
futures = "0.3"
|
||||
tungstenite = "0.13" #websocket
|
||||
serde = "1.0" #serialization
|
||||
tungstenite = "0.17" #websocket
|
||||
serde = { version = "1.0", features = ["derive"] } #serialization
|
||||
html-escape = "0.2"
|
||||
sanitize-filename = "0.3"
|
||||
platform-dirs = "0.3"
|
||||
uuid = { version = "0.8", features = ["v4"] }
|
||||
webbrowser = "0.5"
|
||||
uuid = { version = "1.0", features = ["v4"] }
|
||||
webbrowser = "0.7"
|
||||
libmdns = "0.6" #mDNS advertiser
|
||||
multicast_dns = "0.5" #mDNS browser
|
||||
if-addrs = "0.6"
|
||||
if-addrs = "0.7"
|
||||
base64 = "0.13"
|
||||
scrypt = "0.7"
|
||||
zeroize = "1.2"
|
||||
image = "0.23"
|
||||
scrypt = "0.10"
|
||||
zeroize = "1.5"
|
||||
image = "0.24"
|
||||
yaml-rust = "0.4" #only in debug mode
|
||||
|
||||
[build-dependencies]
|
||||
html-minifier = "3.0"
|
||||
yaml-rust = "0.4"
|
||||
linked-hash-map = "0.5"
|
||||
|
||||
[profile.dev.package.scrypt]
|
||||
opt-level = 3
|
BIN
screenshot.png
BIN
screenshot.png
Binary file not shown.
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 61 KiB |
@ -4,4 +4,5 @@ pub const APPLICATION_FOLDER: &str = "AIRA";
|
||||
pub const DB_NAME: &str = "AIRA.db";
|
||||
pub const HTTP_COOKIE_NAME: &str = "aira_auth";
|
||||
pub const MSG_LOADING_COUNT: usize = 20;
|
||||
pub const FILE_CHUNK_SIZE: usize = 1023996;
|
||||
pub const FILE_CHUNK_SIZE: usize = 1_023_996;
|
||||
pub const MAX_RECV_SIZE: usize = 16_383_996;
|
@ -34,8 +34,8 @@ label {
|
||||
|
||||
.avatar {
|
||||
margin-right: .5em;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
width: 2.5em;
|
||||
height: 2.5em;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
|
79
src/frontend/imgs/icons/logo.svg
Normal file
79
src/frontend/imgs/icons/logo.svg
Normal file
@ -0,0 +1,79 @@
|
||||
<svg width="191.7mm" height="168.39mm" version="1.1" viewBox="0 0 191.7 168.39" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(-9.1475 -20.806)">
|
||||
<path d="m81.908 189.19c14.507-12.545 13.641-67.907 13.641-67.907l18.56 2e-5s-0.86524 55.362 13.641 67.907z" fill="#803300"/>
|
||||
<g fill="#19f52c">
|
||||
<g fill-rule="evenodd">
|
||||
<circle cx="19.053" cy="67.31" r="8.6808"/>
|
||||
<circle cx="40.006" cy="88.061" r="8.6808"/>
|
||||
<circle cx="79.997" cy="99.739" r="8.6808"/>
|
||||
<circle cx="68.203" cy="133.44" r="8.6808"/>
|
||||
<circle cx="105.86" cy="74.321" r="8.6808"/>
|
||||
<circle cx="38.754" cy="131.9" r="8.6808"/>
|
||||
<circle cx="127.11" cy="124.1" r="8.6808"/>
|
||||
<circle cx="97.819" cy="119.49" r="8.6808"/>
|
||||
<circle cx="19.67" cy="109.42" r="8.6808"/>
|
||||
<circle cx="48.138" cy="59.715" r="8.6808"/>
|
||||
<circle cx="95.703" cy="44.581" r="8.6808"/>
|
||||
<circle cx="77.134" cy="67.671" r="8.6808"/>
|
||||
<circle cx="121.04" cy="29.486" r="8.6808"/>
|
||||
<circle cx="119.73" cy="98.423" r="8.6808"/>
|
||||
<circle cx="51.945" cy="108.83" r="8.6808"/>
|
||||
</g>
|
||||
<g stroke="#19f52c" stroke-width="1.8939">
|
||||
<path d="m38.754 131.9-19.084-22.481"/>
|
||||
<path d="m19.67 109.42 20.336-21.356"/>
|
||||
<path d="m19.053 67.31 20.953 20.75"/>
|
||||
<path d="m51.945 108.83 16.258 24.602"/>
|
||||
<path d="m51.945 108.83 28.052-9.0944"/>
|
||||
<path d="m48.138 59.715-8.132 28.346"/>
|
||||
<path d="m48.138 59.715 28.996 7.956"/>
|
||||
<path d="m77.134 67.671 28.73 6.6502"/>
|
||||
<path d="m77.134 67.671 18.569-23.089"/>
|
||||
<path d="m95.703 44.581 25.333-15.095"/>
|
||||
<path d="m105.86 74.321 13.863 24.103"/>
|
||||
<path d="m73.582 133.41 24.237-13.916"/>
|
||||
<path d="m97.819 119.49 21.907-21.071"/>
|
||||
<path d="m97.819 119.49 29.289 4.6056"/>
|
||||
<path d="m17.828 153.33 20.926-21.434"/>
|
||||
</g>
|
||||
<circle cx="17.828" cy="153.33" r="8.6808" fill-rule="evenodd"/>
|
||||
<circle cx="53.865" cy="159.2" r="8.6808" fill-rule="evenodd"/>
|
||||
<path d="m38.754 131.9 15.111 27.303" stroke="#19f52c" stroke-width="1.8939"/>
|
||||
<path d="m127.11 124.1 13.863 24.103" stroke="#19f52c" stroke-width="1.8939"/>
|
||||
<circle cx="140.97" cy="148.2" r="8.6808" fill-rule="evenodd"/>
|
||||
<path d="m140.97 148.2 20.559-17.279" stroke="#19f52c" stroke-width="1.8939"/>
|
||||
<g fill-rule="evenodd">
|
||||
<circle cx="161.53" cy="130.92" r="8.6808"/>
|
||||
<circle cx="148.77" cy="105.42" r="8.6808"/>
|
||||
<circle cx="161.93" cy="80.961" r="8.6808"/>
|
||||
<circle cx="134.44" cy="73.351" r="8.6808"/>
|
||||
<circle cx="172.46" cy="44.584" r="8.6808"/>
|
||||
<circle cx="192.17" cy="132.75" r="8.6808"/>
|
||||
<circle cx="175.39" cy="155.03" r="8.6808"/>
|
||||
<circle cx="68.229" cy="33.867" r="8.6808"/>
|
||||
<circle cx="143.95" cy="45.376" r="8.6808"/>
|
||||
</g>
|
||||
<g stroke="#19f52c" stroke-width="1.8939">
|
||||
<path d="m161.53 130.92 13.863 24.103"/>
|
||||
<path d="m175.39 155.03 16.778-22.271"/>
|
||||
<path d="m119.73 98.423 29.041 6.9934"/>
|
||||
<path d="m148.77 105.42 12.763 25.506"/>
|
||||
<path d="m105.86 74.321 28.58-0.96983"/>
|
||||
<path d="m148.77 105.42 29.455-1.4191"/>
|
||||
<path d="m143.95 45.376 28.511-0.79158"/>
|
||||
<path d="m121.04 29.486 22.914 15.89"/>
|
||||
<path d="m38.754 131.9 29.449 1.5377"/>
|
||||
<path d="m77.134 67.671 2.8632 32.068"/>
|
||||
<path d="m68.229 33.867 27.474 10.715"/>
|
||||
<path d="m48.138 59.715 20.091-25.848"/>
|
||||
<path d="m143.95 45.376-9.5064 27.975"/>
|
||||
</g>
|
||||
<circle cx="178.22" cy="104" r="8.6808" fill-rule="evenodd"/>
|
||||
<path d="m172.46 44.584 16.663 26.606" stroke="#19f52c" stroke-width="1.8939"/>
|
||||
<path d="m134.44 73.351 27.488 7.6103" stroke="#19f52c" stroke-width="1.8939"/>
|
||||
<circle cx="189.12" cy="71.19" r="8.6808" fill-rule="evenodd"/>
|
||||
<path d="m189.12 71.19-27.193 9.7712" stroke="#19f52c" stroke-width="1.8939"/>
|
||||
<path d="m161.93 80.961 16.292 23.036" stroke="#19f52c" stroke-width="1.8939"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.8 KiB |
@ -120,7 +120,7 @@ button:hover::after {
|
||||
position: relative;
|
||||
}
|
||||
#avatarContainer .avatar {
|
||||
font-size: 4em;
|
||||
font-size: 2.5em;
|
||||
}
|
||||
#removeAvatar {
|
||||
position: absolute;
|
||||
@ -149,8 +149,7 @@ button:hover::after {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
#session_info .avatar {
|
||||
width: 6em;
|
||||
height: 6em;
|
||||
font-size: 2.5em;
|
||||
display: block;
|
||||
margin: auto;
|
||||
}
|
||||
@ -198,7 +197,6 @@ button:hover::after {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.7em;
|
||||
cursor: pointer;
|
||||
}
|
||||
#me>div {
|
||||
@ -207,6 +205,7 @@ button:hover::after {
|
||||
flex-grow: 1;
|
||||
}
|
||||
#me p {
|
||||
font-size: 1.7em;
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
display: inline;
|
||||
@ -214,6 +213,9 @@ button:hover::after {
|
||||
#me>div:hover p {
|
||||
color: var(--accent);
|
||||
}
|
||||
#me .avatar {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
#left_panel ul:last-of-type, #msg_log {
|
||||
flex-grow: 1;
|
||||
}
|
||||
@ -235,8 +237,7 @@ button:hover::after {
|
||||
flex-grow: 1;
|
||||
}
|
||||
#left_panel ul li .avatar {
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
font-size: .9em;
|
||||
}
|
||||
#left_panel ul li:hover, #left_panel ul li.current {
|
||||
background-color: #333940;
|
||||
@ -254,7 +255,8 @@ button:hover::after {
|
||||
#left_panel ul li.is_verified p::after {
|
||||
content: url("/static/imgs/icons/verified/ACCENT_COLOR");
|
||||
}
|
||||
#left_panel ul li .not_seen_marker {
|
||||
#left_panel ul li.not_seen::after {
|
||||
content: "";
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-color: var(--accent);
|
||||
@ -295,7 +297,6 @@ button:hover::after {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 20px 20px;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
#chat_header>div {
|
||||
display: flex;
|
||||
@ -307,6 +308,7 @@ button:hover::after {
|
||||
color: var(--accent);
|
||||
}
|
||||
#chat_header>div>p { /*name*/
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
}
|
||||
@ -354,7 +356,6 @@ button:hover::after {
|
||||
}
|
||||
#file_transfer {
|
||||
border-top: 2px solid var(--accent);
|
||||
display: none;
|
||||
position: relative;
|
||||
}
|
||||
#file_transfer.active {
|
||||
@ -401,31 +402,46 @@ button:hover::after {
|
||||
height: 100%;
|
||||
background-color: var(--accent);
|
||||
}
|
||||
#message_box {
|
||||
border-top: 2px solid var(--accent);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
#msg_log {
|
||||
font-size: 1.1em;
|
||||
overflow-y: scroll;
|
||||
white-space: pre;
|
||||
overflow-y: auto;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
#msg_log li {
|
||||
display: flex;
|
||||
align-items: end;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
#msg_log li>div {
|
||||
flex-grow: 1;
|
||||
}
|
||||
#msg_log li .timestamp {
|
||||
opacity: .5;
|
||||
font-family: "Liberation Sans", Arial, sans-serif;
|
||||
font-size: .8em;
|
||||
}
|
||||
#msg_log p {
|
||||
font-size: 1.1em;
|
||||
margin: 0;
|
||||
}
|
||||
#msg_log .avatar {
|
||||
font-size: .8em;
|
||||
}
|
||||
#msg_log li .header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 15px;
|
||||
}
|
||||
#msg_log li .header p {
|
||||
color: var(--accent);
|
||||
font-weight: bold;
|
||||
margin-left: .5em;
|
||||
}
|
||||
#msg_log li .content {
|
||||
margin-left: 2em;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 3em;
|
||||
}
|
||||
#msg_log li .content p {
|
||||
word-break: break-word;
|
||||
}
|
||||
#msg_log a {
|
||||
color: #238cf5;
|
||||
@ -452,6 +468,149 @@ button:hover::after {
|
||||
width: 2em;
|
||||
margin-left: 15px;
|
||||
}
|
||||
#message_box, #chat_header, #msg_log {
|
||||
#message_box, #message_box.online #offline_warning, #chat_header, #msg_log, #file_transfer {
|
||||
display: none;
|
||||
}
|
||||
#message_box.active {
|
||||
display: block;
|
||||
}
|
||||
#message_box {
|
||||
border-top: 2px solid red;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
#message_box>div:nth-child(2) {
|
||||
display: flex;
|
||||
}
|
||||
#message_box.online {
|
||||
border-top-color: var(--accent);
|
||||
}
|
||||
#offline_warning {
|
||||
margin-left: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 25px;
|
||||
}
|
||||
#offline_warning::before {
|
||||
content: url("/static/imgs/icons/warning/ff0000");
|
||||
display: block;
|
||||
width: 2em;
|
||||
}
|
||||
#offline_warning h3 {
|
||||
color: red;
|
||||
display: inline-block;
|
||||
margin-bottom: .3em;
|
||||
}
|
||||
#offline_warning p {
|
||||
margin-top: 0;
|
||||
}
|
||||
#msg_log li.pending_msgs_divider {
|
||||
border-top: 1px solid grey;
|
||||
padding-top: 10px;
|
||||
margin-top: 30px;
|
||||
margin-left: 100px;
|
||||
margin-right: 100px;
|
||||
}
|
||||
#msg_log li.pending_msgs_divider h4 {
|
||||
margin: auto;
|
||||
opacity: .5;
|
||||
}
|
||||
.lds-spinner {
|
||||
color: official;
|
||||
position: relative;
|
||||
width: 82px;
|
||||
height: 82px;
|
||||
}
|
||||
.lds-spinner div {
|
||||
transform-origin: 40px 40px;
|
||||
animation: lds-spinner 1.2s linear infinite;
|
||||
}
|
||||
.lds-spinner div:after {
|
||||
content: " ";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
left: 37px;
|
||||
width: 6px;
|
||||
height: 18px;
|
||||
border-radius: 20%;
|
||||
background: #fff;
|
||||
}
|
||||
.lds-spinner div:nth-child(1) {
|
||||
transform: rotate(0deg);
|
||||
animation-delay: -1.1s;
|
||||
}
|
||||
.lds-spinner div:nth-child(2) {
|
||||
transform: rotate(30deg);
|
||||
animation-delay: -1s;
|
||||
}
|
||||
.lds-spinner div:nth-child(3) {
|
||||
transform: rotate(60deg);
|
||||
animation-delay: -0.9s;
|
||||
}
|
||||
.lds-spinner div:nth-child(4) {
|
||||
transform: rotate(90deg);
|
||||
animation-delay: -0.8s;
|
||||
}
|
||||
.lds-spinner div:nth-child(5) {
|
||||
transform: rotate(120deg);
|
||||
animation-delay: -0.7s;
|
||||
}
|
||||
.lds-spinner div:nth-child(6) {
|
||||
transform: rotate(150deg);
|
||||
animation-delay: -0.6s;
|
||||
}
|
||||
.lds-spinner div:nth-child(7) {
|
||||
transform: rotate(180deg);
|
||||
animation-delay: -0.5s;
|
||||
}
|
||||
.lds-spinner div:nth-child(8) {
|
||||
transform: rotate(210deg);
|
||||
animation-delay: -0.4s;
|
||||
}
|
||||
.lds-spinner div:nth-child(9) {
|
||||
transform: rotate(240deg);
|
||||
animation-delay: -0.3s;
|
||||
}
|
||||
.lds-spinner div:nth-child(10) {
|
||||
transform: rotate(270deg);
|
||||
animation-delay: -0.2s;
|
||||
}
|
||||
.lds-spinner div:nth-child(11) {
|
||||
transform: rotate(300deg);
|
||||
animation-delay: -0.1s;
|
||||
}
|
||||
.lds-spinner div:nth-child(12) {
|
||||
transform: rotate(330deg);
|
||||
animation-delay: 0s;
|
||||
}
|
||||
@keyframes lds-spinner {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
#pending_msgs_indicator {
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
#pending_msgs_indicator.sending {
|
||||
display: flex;
|
||||
}
|
||||
#disconnected {
|
||||
display: none;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
#disconnected.disconnected {
|
||||
display: flex;
|
||||
}
|
||||
#disconnected img {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>AIRA</title>
|
||||
<link rel="icon" type="image/svg" href="/static/imgs/icons/logo">
|
||||
<link rel="stylesheet" href="/static/commons/style.css">
|
||||
<link rel="stylesheet" href="/static/index.css">
|
||||
</head>
|
||||
@ -41,6 +42,10 @@
|
||||
</div>
|
||||
<ul id="msg_log">
|
||||
</ul>
|
||||
<div id="pending_msgs_indicator">
|
||||
<div class="lds-spinner"><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div>
|
||||
<h3>Sending pending messages...</h3>
|
||||
</div>
|
||||
<div id="file_transfer">
|
||||
<div id="file_control">
|
||||
<button id="file_cancel" title="Cancel"></button>
|
||||
@ -56,10 +61,22 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id="message_box">
|
||||
<input type="text" id="message_input" placeholder="Send a message...">
|
||||
<label title="Send file" class="file_picker">
|
||||
<input type="file" id="attach_file" multiple>
|
||||
</label>
|
||||
<div id="offline_warning">
|
||||
<div>
|
||||
<h3>Your contact seems to be offline.</h3>
|
||||
<p>Sent messages will be stored until a connection is established.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<input type="text" id="message_input" placeholder="Send a message...">
|
||||
<label title="Send file" class="file_picker">
|
||||
<input type="file" id="attach_file" multiple>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="disconnected">
|
||||
<img src="/static/imgs/icons/warning/ff0000">
|
||||
<h1>Websocket connection closed</h1>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
@ -76,4 +93,3 @@
|
||||
<script src="/static/index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
"use strict";
|
||||
|
||||
let identityName = undefined;
|
||||
let socket = null;
|
||||
let socket = new WebSocket("ws://"+location.hostname+":"+websocketPort+"/ws");;
|
||||
let notificationAllowed = false;
|
||||
let localIps = [];
|
||||
let currentSessionId = -1;
|
||||
let sessionsData = new Map();
|
||||
let msgHistory = new Map();
|
||||
let pendingMsgs = new Map();
|
||||
let pendingFilesTransfers = new Map();
|
||||
let avatarTimestamps = new Map([
|
||||
["self", Date.now()]
|
||||
@ -14,7 +15,7 @@ let avatarTimestamps = new Map([
|
||||
|
||||
function onClickSession(event) {
|
||||
let sessionId = event.currentTarget.getAttribute("data-sessionId");
|
||||
if (sessionId != null) {
|
||||
if (sessionId != null && socket.readyState === WebSocket.OPEN) {
|
||||
currentSessionId = sessionId;
|
||||
let session = sessionsData.get(sessionId);
|
||||
if (!session.seen) {
|
||||
@ -80,6 +81,7 @@ document.getElementById("delete_conversation").onclick = function() {
|
||||
document.getElementById("add_contact").onclick = function() {
|
||||
socket.send("contact "+currentSessionId);
|
||||
sessionsData.get(currentSessionId).isContact = true;
|
||||
pendingMsgs.set(currentSessionId, []);
|
||||
displayHeader();
|
||||
displaySessions();
|
||||
};
|
||||
@ -103,7 +105,9 @@ document.getElementById("remove_contact").onclick = function() {
|
||||
if (!session.isOnline) {
|
||||
sessionsData.delete(currentSessionId);
|
||||
msgHistory.get(currentSessionId).length = 0;
|
||||
displayChatBottom();
|
||||
}
|
||||
pendingMsgs.delete(currentSessionId);
|
||||
displayHeader();
|
||||
displaySessions();
|
||||
displayHistory();
|
||||
@ -174,7 +178,7 @@ document.getElementById("attach_file").onchange = function(event) {
|
||||
let files = event.target.files;
|
||||
let useLargeFileTransfer = false;
|
||||
for (let i=0; i<files.length; ++i) {
|
||||
if (files[i].size > 32760000) {
|
||||
if (files[i].size > 16380000) {
|
||||
useLargeFileTransfer = true;
|
||||
break;
|
||||
}
|
||||
@ -215,7 +219,11 @@ document.getElementById("attach_file").onchange = function(event) {
|
||||
formData.append("", files[i]);
|
||||
fetch("/send_file", {method: "POST", body: formData}).then(response => {
|
||||
if (response.ok) {
|
||||
response.text().then(uuid => onFileSent(currentSessionId, uuid, files[i].name));
|
||||
response.text().then(text => {
|
||||
if (text === "pending") {
|
||||
newPendingMsg(currentSessionId, true, files[i].name);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log(response);
|
||||
}
|
||||
@ -226,16 +234,19 @@ document.getElementById("attach_file").onchange = function(event) {
|
||||
document.getElementById("file_cancel").onclick = function() {
|
||||
socket.send("abort "+currentSessionId);
|
||||
};
|
||||
let msg_log = document.getElementById("msg_log");
|
||||
msg_log.onscroll = function() {
|
||||
if (sessionsData.get(currentSessionId).isContact) {
|
||||
if (msg_log.scrollTop < 30) {
|
||||
socket.send("load_msgs "+currentSessionId);
|
||||
let msgLog = document.getElementById("msg_log");
|
||||
msgLog.onscroll = function() {
|
||||
let session = sessionsData.get(currentSessionId);
|
||||
if (typeof session !== "undefined") {
|
||||
if (session.isContact) {
|
||||
if (msgLog.scrollTop < 30) {
|
||||
socket.send("load_msgs "+currentSessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let profile_div = document.querySelector("#me>div");
|
||||
profile_div.onclick = function() {
|
||||
let profileDiv = document.querySelector("#me>div");
|
||||
profileDiv.onclick = function() {
|
||||
let mainDiv = document.createElement("div");
|
||||
mainDiv.id = "profile_info";
|
||||
let avatarContainer = document.createElement("div");
|
||||
@ -324,32 +335,35 @@ profile_div.onclick = function() {
|
||||
changePasswordButton.textContent = "Change password";
|
||||
changePasswordButton.onclick = function() {
|
||||
let inputs = document.querySelectorAll("input[type=\"password\"]");
|
||||
let newPassword, newPasswordConfirm;
|
||||
let newPassword, newPasswordConfirm, oldPassword;
|
||||
if (isIdentityProtected) {
|
||||
newPassword = inputs[1];
|
||||
newPasswordConfirm = inputs[2];
|
||||
oldPassword = inputs[0].value;
|
||||
newPassword = inputs[1].value;
|
||||
newPasswordConfirm = inputs[2].value;
|
||||
} else {
|
||||
newPassword = inputs[0];
|
||||
newPasswordConfirm = inputs[1];
|
||||
newPassword = inputs[0].value;
|
||||
newPasswordConfirm = inputs[1].value;
|
||||
}
|
||||
if (newPassword.value == newPasswordConfirm.value) {
|
||||
let newPassword_set = newPassword.value.length > 0;
|
||||
if (isIdentityProtected || newPassword_set) { //don't change password if identity is not protected and new password is blank
|
||||
if (newPassword == newPasswordConfirm) {
|
||||
let newPasswordSet = newPassword.length > 0;
|
||||
if (isIdentityProtected && oldPassword.length == 0) {
|
||||
errorMsg.textContent = "Current password cannot be empty.";
|
||||
} else if (isIdentityProtected || newPasswordSet) { //don't change password if identity is not protected and new password is blank
|
||||
let msg = "change_password";
|
||||
if (isIdentityProtected) {
|
||||
msg += " "+b64EncodeUnicode(inputs[0].value);
|
||||
}
|
||||
if (newPassword_set) {
|
||||
msg += " "+b64EncodeUnicode(newPassword.value);
|
||||
if (newPasswordSet) {
|
||||
msg += " "+b64EncodeUnicode(newPassword);
|
||||
}
|
||||
socket.send(msg);
|
||||
} else {
|
||||
removePopup();
|
||||
}
|
||||
} else {
|
||||
newPassword.value = "";
|
||||
newPasswordConfirm.value = "";
|
||||
errorMsg.textContent = "Passwords don't match";
|
||||
newPassword = "";
|
||||
newPasswordConfirm = "";
|
||||
errorMsg.textContent = "Passwords don't match.";
|
||||
}
|
||||
};
|
||||
sectionPassword.appendChild(changePasswordButton);
|
||||
@ -436,8 +450,17 @@ function getCookie(cname) {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
function parseTimestamp(timestamp) {
|
||||
return new Date(Number(timestamp) * 1000);
|
||||
}
|
||||
function toTwoNumbers(n) {
|
||||
if (n < 10) {
|
||||
return '0'+n;
|
||||
} else {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
socket = new WebSocket("ws://"+location.hostname+":"+websocketPort+"/ws");
|
||||
socket.onopen = function() {
|
||||
console.log("Connected");
|
||||
socket.send(getCookie("aira_auth")); //authenticating websocket connection
|
||||
@ -468,10 +491,10 @@ socket.onmessage = function(msg) {
|
||||
onNewSession(args[1], args[2] === "true", args[3], args[4], msg.data.slice(args[0].length+args[1].length+args[2].length+args[3].length+args[4].length+5));
|
||||
break;
|
||||
case "new_message":
|
||||
onNewMessage(args[1], args[2] === "true", msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
||||
onNewMessage(args[1], args[2] === "true", parseTimestamp(args[3]), msg.data.slice(args[0].length+args[1].length+args[2].length+args[3].length+4));
|
||||
break;
|
||||
case "file":
|
||||
onFileReceived(args[1], args[2], msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
||||
onNewFile(args[1], args[2] === "true", parseTimestamp(args[3]), args[4], msg.data.slice(args[0].length+args[1].length+args[2].length+args[3].length+args[4].length+5));
|
||||
break;
|
||||
case "files_transfer":
|
||||
onNewFilesTransfer(args[1], args[2], msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
||||
@ -500,6 +523,15 @@ socket.onmessage = function(msg) {
|
||||
case "not_seen":
|
||||
setNotSeen(msg.data.slice(args[0].length+1));
|
||||
break;
|
||||
case "pending":
|
||||
newPendingMsg(args[1], args[2] === "true", msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
||||
break;
|
||||
case "sending_pending_msgs":
|
||||
onSendingPendingMsgs(args[1]);
|
||||
break;
|
||||
case "pending_msgs_sent":
|
||||
onPendingMsgsSent(args[1]);
|
||||
break;
|
||||
case "local_ips":
|
||||
setLocalIps(msg.data.slice(args[0].length+1));
|
||||
break;
|
||||
@ -519,6 +551,12 @@ socket.onmessage = function(msg) {
|
||||
};
|
||||
socket.onclose = function() {
|
||||
console.log("Disconnected");
|
||||
currentSessionId = -1;
|
||||
displayHistory();
|
||||
displayHeader();
|
||||
displayChatBottom();
|
||||
displaySessions();
|
||||
document.getElementById("disconnected").classList.add("disconnected");
|
||||
};
|
||||
|
||||
function onNewSession(sessionId, outgoing, fingerprint, ip, name) {
|
||||
@ -564,6 +602,22 @@ function setNotSeen(strSessionIds) {
|
||||
}
|
||||
displaySessions();
|
||||
}
|
||||
function newPendingMsg(sessionId, isFile, data) {
|
||||
pendingMsgs.get(sessionId).push([isFile, data]);
|
||||
if (sessionId == currentSessionId) {
|
||||
displayHistory();
|
||||
}
|
||||
}
|
||||
function onSendingPendingMsgs(sessionId) {
|
||||
document.getElementById("pending_msgs_indicator").classList.add("sending");
|
||||
pendingMsgs.get(sessionId).length = 0;
|
||||
if (sessionId == currentSessionId) {
|
||||
displayHistory();
|
||||
}
|
||||
}
|
||||
function onPendingMsgsSent(sessionId) {
|
||||
document.getElementById("pending_msgs_indicator").classList.remove("sending");
|
||||
}
|
||||
function setLocalIps(strIPs) {
|
||||
localIps = strIPs.split(' ');
|
||||
}
|
||||
@ -576,6 +630,7 @@ function onIsContact(sessionId, verified, fingerprint, name) {
|
||||
} else {
|
||||
addSession(sessionId, name, undefined, fingerprint, undefined, true, verified, false);
|
||||
}
|
||||
pendingMsgs.set(sessionId, []);
|
||||
}
|
||||
function onMsgOrFileReceived(sessionId, outgoing, body) {
|
||||
if (currentSessionId == sessionId) {
|
||||
@ -589,16 +644,22 @@ function onMsgOrFileReceived(sessionId, outgoing, body) {
|
||||
}
|
||||
if (document.hidden && !outgoing) {
|
||||
if (notificationAllowed) {
|
||||
new Notification(sessionsData.get(sessionId).name, {
|
||||
"body": body
|
||||
let sessionName = sessionsData.get(sessionId).name;
|
||||
new Notification(sessionName, {
|
||||
"body": body,
|
||||
"icon": "/avatar/"+sessionId+"/"+sessionName+"?"+avatarTimestamps.get(sessionId)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
function onNewMessage(sessionId, outgoing, msg) {
|
||||
msgHistory.get(sessionId).push([outgoing, false, msg]);
|
||||
function onNewMessage(sessionId, outgoing, timestamp, msg) {
|
||||
msgHistory.get(sessionId).push([outgoing, timestamp, false, msg]);
|
||||
onMsgOrFileReceived(sessionId, outgoing, msg);
|
||||
}
|
||||
function onNewFile(sessionId, outgoing, timestamp, uuid, filename) {
|
||||
msgHistory.get(sessionId).push([outgoing, timestamp, true, [uuid, filename]]);
|
||||
onMsgOrFileReceived(sessionId, outgoing, filename);
|
||||
}
|
||||
function onNewFilesTransfer(sessionId, index, filesInfo) {
|
||||
let split = filesInfo.split(' ');
|
||||
let files = [];
|
||||
@ -683,7 +744,8 @@ function onAskLargeFiles(sessionId, encodedDownloadLocation, filesInfo) {
|
||||
showPopup(mainDiv, false);
|
||||
if (document.hidden && notificationAllowed) {
|
||||
new Notification(sessionName, {
|
||||
"body": "Files download request"
|
||||
"body": "Files download request",
|
||||
"icon": "/avatar/"+sessionId+"/"+sessionName+"?"+avatarTimestamps.get(sessionId)
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -726,29 +788,32 @@ function onIncFilesTransfer(sessionId, chunkSize) {
|
||||
}
|
||||
function onMsgsLoad(sessionId, strMsgs) {
|
||||
let msgs = strMsgs.split(' ');
|
||||
let n = 0;
|
||||
while (n < msgs.length) {
|
||||
let outgoing = msgs[n+1] === "true";
|
||||
switch (msgs[n]) {
|
||||
case 'm':
|
||||
let msg = b64DecodeUnicode(msgs[n+2]);
|
||||
msgHistory.get(sessionId).unshift([outgoing, false, msg]);
|
||||
n += 3;
|
||||
break;
|
||||
case 'f':
|
||||
let uuid = msgs[n+2];
|
||||
let fileName = b64DecodeUnicode(msgs[n+3]);
|
||||
msgHistory.get(sessionId).unshift([outgoing, true, [uuid, fileName]]);
|
||||
n += 4;
|
||||
if (msgs.length > 3) {
|
||||
let n = 0;
|
||||
while (n < msgs.length) {
|
||||
let outgoing = msgs[n+1] === "true";
|
||||
let timestamp = parseTimestamp(msgs[n+2]);
|
||||
switch (msgs[n]) {
|
||||
case 'm':
|
||||
let msg = b64DecodeUnicode(msgs[n+3]);
|
||||
msgHistory.get(sessionId).unshift([outgoing, timestamp, false, msg]);
|
||||
n += 4;
|
||||
break;
|
||||
case 'f':
|
||||
let uuid = msgs[n+3];
|
||||
let fileName = b64DecodeUnicode(msgs[n+4]);
|
||||
msgHistory.get(sessionId).unshift([outgoing, timestamp, true, [uuid, fileName]]);
|
||||
n += 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentSessionId == sessionId) {
|
||||
if (msg_log.scrollHeight - msg_log.scrollTop === msg_log.clientHeight) {
|
||||
displayHistory();
|
||||
} else {
|
||||
let backupHeight = msg_log.scrollHeight;
|
||||
displayHistory(false);
|
||||
msg_log.scrollTop = msg_log.scrollHeight-backupHeight;
|
||||
if (currentSessionId == sessionId) {
|
||||
if (msgLog.scrollHeight - msgLog.scrollTop === msgLog.clientHeight) {
|
||||
displayHistory();
|
||||
} else {
|
||||
let backupHeight = msgLog.scrollHeight;
|
||||
displayHistory(false);
|
||||
msgLog.scrollTop = msgLog.scrollHeight-backupHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -762,6 +827,7 @@ function onDisconnected(sessionId) {
|
||||
}
|
||||
if (currentSessionId == sessionId) {
|
||||
displayChatBottom();
|
||||
scrollHistoryToBottom();
|
||||
}
|
||||
if (currentSessionId == sessionId && !session.isContact) {
|
||||
currentSessionId = -1;
|
||||
@ -769,16 +835,6 @@ function onDisconnected(sessionId) {
|
||||
}
|
||||
displaySessions();
|
||||
}
|
||||
function onFileReceived(sessionId, uuid, file_name) {
|
||||
msgHistory.get(sessionId).push([false, true, [uuid, file_name]]);
|
||||
onMsgOrFileReceived(sessionId, false, file_name);
|
||||
}
|
||||
function onFileSent(sessionId, uuid, file_name) {
|
||||
msgHistory.get(sessionId).push([true, true, [uuid, file_name]]);
|
||||
if (currentSessionId == sessionId) {
|
||||
displayHistory();
|
||||
}
|
||||
}
|
||||
function onNameSet(newName) {
|
||||
removePopup();
|
||||
identityName = newName;
|
||||
@ -925,11 +981,11 @@ function logout() {
|
||||
window.location = "/logout";
|
||||
}
|
||||
function displayProfile() {
|
||||
profile_div.innerHTML = "";
|
||||
profile_div.appendChild(generateSelfAvatar(avatarTimestamps.get("self")));
|
||||
profileDiv.innerHTML = "";
|
||||
profileDiv.appendChild(generateSelfAvatar(avatarTimestamps.get("self")));
|
||||
let p = document.createElement("p");
|
||||
p.textContent = identityName;
|
||||
profile_div.appendChild(p);
|
||||
profileDiv.appendChild(p);
|
||||
}
|
||||
function displayHeader() {
|
||||
chatHeader.children[0].innerHTML = "";
|
||||
@ -1002,9 +1058,7 @@ function generateSession(sessionId, session) {
|
||||
li.classList.add("is_verified");
|
||||
}
|
||||
if (!session.seen) {
|
||||
let marker = document.createElement("div");
|
||||
marker.classList.add("not_seen_marker");
|
||||
li.appendChild(marker);
|
||||
li.classList.add("not_seen");
|
||||
}
|
||||
if (sessionId == currentSessionId) {
|
||||
li.classList.add("current");
|
||||
@ -1027,20 +1081,27 @@ function generateMsgHeader(name, sessionId) {
|
||||
div.appendChild(p);
|
||||
return div;
|
||||
}
|
||||
function generateMessageTimestamp(timestamp) {
|
||||
let p = document.createElement("p");
|
||||
p.classList.add("timestamp");
|
||||
p.title = timestamp;
|
||||
p.textContent = toTwoNumbers(timestamp.getHours())+":"+toTwoNumbers(timestamp.getMinutes());
|
||||
return p;
|
||||
}
|
||||
function generateMessage(name, sessionId, msg) {
|
||||
let p = document.createElement("p");
|
||||
p.appendChild(document.createTextNode(msg));
|
||||
let div = document.createElement("div");
|
||||
div.classList.add("content");
|
||||
div.appendChild(linkifyElement(p));
|
||||
let li = document.createElement("li");
|
||||
let divContainer = document.createElement("div");
|
||||
if (typeof name !== "undefined") {
|
||||
li.appendChild(generateMsgHeader(name, sessionId));
|
||||
divContainer.appendChild(generateMsgHeader(name, sessionId));
|
||||
}
|
||||
li.appendChild(div);
|
||||
return li;
|
||||
divContainer.appendChild(div);
|
||||
return divContainer;
|
||||
}
|
||||
function generateFile(name, sessionId, outgoing, file_info) {
|
||||
function generateFile(name, sessionId, outgoing, fileInfo) {
|
||||
let div1 = document.createElement("div");
|
||||
div1.classList.add("file");
|
||||
div1.classList.add("content");
|
||||
@ -1052,20 +1113,24 @@ function generateFile(name, sessionId, outgoing, file_info) {
|
||||
h4.textContent = "File received:";
|
||||
}
|
||||
div2.appendChild(h4);
|
||||
let p = document.createElement("p");
|
||||
p.textContent = file_info[1];
|
||||
div2.appendChild(p);
|
||||
div1.appendChild(div2);
|
||||
let a = document.createElement("a");
|
||||
a.href = "/load_file?uuid="+file_info[0]+"&file_name="+encodeURIComponent(file_info[1]);
|
||||
a.target = "_blank";
|
||||
div1.appendChild(a);
|
||||
let li = document.createElement("li");
|
||||
if (typeof name !== "undefined") {
|
||||
li.appendChild(generateMsgHeader(name, sessionId));
|
||||
let p = document.createElement("p");
|
||||
if (typeof fileInfo === "string") { //pending
|
||||
p.textContent = fileInfo;
|
||||
} else {
|
||||
p.textContent = fileInfo[1];
|
||||
let a = document.createElement("a");
|
||||
a.href = "/load_file?uuid="+fileInfo[0]+"&file_name="+encodeURIComponent(fileInfo[1]);
|
||||
a.target = "_blank";
|
||||
div1.appendChild(a);
|
||||
}
|
||||
li.appendChild(div1);
|
||||
return li;
|
||||
div2.appendChild(p);
|
||||
let divContainer = document.createElement("div");
|
||||
if (typeof name !== "undefined") {
|
||||
divContainer.appendChild(generateMsgHeader(name, sessionId));
|
||||
}
|
||||
divContainer.appendChild(div1);
|
||||
return divContainer;
|
||||
}
|
||||
function generateFileInfo(fileName, fileSize, p) {
|
||||
let span = document.createElement("span");
|
||||
@ -1078,13 +1143,16 @@ function displayChatBottom(speed = undefined) {
|
||||
let fileTransfer = document.getElementById("file_transfer");
|
||||
let session = sessionsData.get(currentSessionId);
|
||||
if (typeof session === "undefined") {
|
||||
msgBox.removeAttribute("style");
|
||||
msgBox.classList.remove("active");
|
||||
fileTransfer.classList.remove("active");
|
||||
} else {
|
||||
if (session.isContact || session.isOnline) {
|
||||
msgBox.classList.add("active");
|
||||
}
|
||||
if (session.isOnline) {
|
||||
msgBox.style.display = "flex";
|
||||
msgBox.classList.add("online");
|
||||
} else {
|
||||
msgBox.removeAttribute("style");
|
||||
msgBox.classList.remove("online");
|
||||
}
|
||||
if (pendingFilesTransfers.has(currentSessionId)) {
|
||||
let fileInfo = document.getElementById("file_info");
|
||||
@ -1129,35 +1197,72 @@ function displayChatBottom(speed = undefined) {
|
||||
}
|
||||
}
|
||||
}
|
||||
function scrollHistoryToBottom() {
|
||||
msgLog.scrollTop = msgLog.scrollHeight;
|
||||
}
|
||||
function displayHistory(scrollToBottom = true) {
|
||||
msg_log.style.display = "block";
|
||||
msg_log.innerHTML = "";
|
||||
msgLog.innerHTML = "";
|
||||
let session = sessionsData.get(currentSessionId);
|
||||
let previousOutgoing = undefined;
|
||||
msgHistory.get(currentSessionId).forEach(entry => {
|
||||
let name = undefined;
|
||||
let sessionId = undefined;
|
||||
if (previousOutgoing != entry[0]) {
|
||||
previousOutgoing = entry[0];
|
||||
if (entry[0]) { //outgoing msg
|
||||
name = identityName;
|
||||
if (typeof session === "undefined") {
|
||||
msgLog.style.display = "none";
|
||||
} else {
|
||||
msgLog.style.display = "block";
|
||||
let previousOutgoing = undefined;
|
||||
msgHistory.get(currentSessionId).forEach(entry => {
|
||||
let name = undefined;
|
||||
let sessionId = undefined;
|
||||
if (previousOutgoing != entry[0]) {
|
||||
previousOutgoing = entry[0];
|
||||
if (entry[0]) { //outgoing msg
|
||||
name = identityName;
|
||||
} else {
|
||||
name = session.name;
|
||||
sessionId = currentSessionId;
|
||||
}
|
||||
}
|
||||
let div;
|
||||
if (entry[2]) { //is file
|
||||
div = generateFile(name, sessionId, entry[0], entry[3]);
|
||||
} else {
|
||||
name = session.name;
|
||||
sessionId = currentSessionId;
|
||||
div = generateMessage(name, sessionId, entry[3]);
|
||||
}
|
||||
let li = document.createElement("li");
|
||||
li.appendChild(div);
|
||||
li.appendChild(generateMessageTimestamp(entry[1]));
|
||||
msgLog.appendChild(li);
|
||||
});
|
||||
if (session.isContact) {
|
||||
let msgs = pendingMsgs.get(currentSessionId);
|
||||
if (msgs.length > 0) {
|
||||
let li = document.createElement("li");
|
||||
li.classList.add("pending_msgs_divider");
|
||||
let h4 = document.createElement("h4");
|
||||
h4.textContent = "Pending messages:";
|
||||
li.appendChild(h4);
|
||||
msgLog.appendChild(li);
|
||||
msgs.forEach(entry => {
|
||||
let name = undefined;
|
||||
if (previousOutgoing != true) {
|
||||
previousOutgoing = true;
|
||||
name = identityName;
|
||||
}
|
||||
let div;
|
||||
if (entry[0]) { //is file
|
||||
div = generateFile(name, undefined, true, entry[1]);
|
||||
} else {
|
||||
div = generateMessage(name, undefined, entry[1]);
|
||||
}
|
||||
let li = document.createElement("li");
|
||||
li.appendChild(div);
|
||||
msgLog.appendChild(li);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (entry[1]) { //is file
|
||||
msg_log.appendChild(generateFile(name, sessionId, entry[0], entry[2]));
|
||||
} else {
|
||||
msg_log.appendChild(generateMessage(name, sessionId, entry[2]));
|
||||
if (scrollToBottom) {
|
||||
scrollHistoryToBottom();
|
||||
}
|
||||
});
|
||||
if (scrollToBottom) {
|
||||
msg_log.scrollTop = msg_log.scrollHeight;
|
||||
}
|
||||
if (typeof session !== "undefined") {
|
||||
if (msg_log.scrollHeight <= msg_log.clientHeight && session.isContact) {
|
||||
if (msgLog.scrollHeight <= msgLog.clientHeight && session.isContact) {
|
||||
socket.send("load_msgs "+currentSessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>AIRA - Login</title>
|
||||
<link rel="icon" type="image/svg" href="/static/imgs/icons/logo">
|
||||
<link rel="stylesheet" href="/static/commons/style.css">
|
||||
<style>
|
||||
body {
|
||||
@ -58,8 +59,7 @@
|
||||
padding: 10px 50px;
|
||||
}
|
||||
.avatar {
|
||||
width: 7em;
|
||||
height: 7em;
|
||||
font-size: 3em;
|
||||
}
|
||||
#identity h2 {
|
||||
text-align: center;
|
||||
|
@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>AIRA - Logged out</title>
|
||||
<link rel="icon" type="image/svg" href="/static/imgs/icons/logo">
|
||||
<link rel="stylesheet" href="/static/commons/style.css">
|
||||
<style>
|
||||
body {
|
||||
|
124
src/identity.rs
124
src/identity.rs
@ -43,12 +43,11 @@ fn get_database_path() -> String {
|
||||
AppDirs::new(Some(constants::APPLICATION_FOLDER), false).unwrap().data_dir.join(constants::DB_NAME).to_str().unwrap().to_owned()
|
||||
}
|
||||
|
||||
struct EncryptedIdentity {
|
||||
name: String,
|
||||
encrypted_keypair: Vec<u8>,
|
||||
salt: Vec<u8>,
|
||||
encrypted_master_key: Vec<u8>,
|
||||
encrypted_use_padding: Vec<u8>,
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Message {
|
||||
pub outgoing: bool,
|
||||
pub timestamp: u64,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
pub struct Contact {
|
||||
@ -60,6 +59,14 @@ pub struct Contact {
|
||||
pub seen: bool,
|
||||
}
|
||||
|
||||
struct EncryptedIdentity {
|
||||
name: String,
|
||||
encrypted_keypair: Vec<u8>,
|
||||
salt: Vec<u8>,
|
||||
encrypted_master_key: Vec<u8>,
|
||||
encrypted_use_padding: Vec<u8>,
|
||||
}
|
||||
|
||||
pub struct Identity {
|
||||
pub name: String,
|
||||
pub keypair: Keypair,
|
||||
@ -87,8 +94,8 @@ impl Identity {
|
||||
};
|
||||
Ok(Contact {
|
||||
uuid: contact_uuid,
|
||||
public_key: public_key,
|
||||
name: name,
|
||||
public_key,
|
||||
name,
|
||||
avatar: avatar_uuid,
|
||||
verified: false,
|
||||
seen: true,
|
||||
@ -242,16 +249,17 @@ impl Identity {
|
||||
Ok(file_uuid)
|
||||
}
|
||||
|
||||
pub fn store_msg(&self, contact_uuid: &Uuid, outgoing: bool, data: &[u8]) -> Result<usize, rusqlite::Error> {
|
||||
pub fn store_msg(&self, contact_uuid: &Uuid, message: &Message) -> Result<usize, rusqlite::Error> {
|
||||
let db = Connection::open(get_database_path())?;
|
||||
db.execute(&format!("CREATE TABLE IF NOT EXISTS \"{}\" (outgoing BLOB, data BLOB)", contact_uuid), [])?;
|
||||
let outgoing_byte: u8 = bool_to_byte(outgoing);
|
||||
db.execute(&format!("CREATE TABLE IF NOT EXISTS \"{}\" (outgoing BLOB, timestamp BLOB, data BLOB)", contact_uuid), [])?;
|
||||
let outgoing_byte: u8 = bool_to_byte(message.outgoing);
|
||||
let encrypted_outgoing = crypto::encrypt_data(&[outgoing_byte], &self.master_key).unwrap();
|
||||
let encrypted_data = crypto::encrypt_data(data, &self.master_key).unwrap();
|
||||
db.execute(&format!("INSERT INTO \"{}\" (outgoing, data) VALUES (?1, ?2)", contact_uuid), params![encrypted_outgoing, encrypted_data])
|
||||
let encrypted_timestamp = crypto::encrypt_data(&message.timestamp.to_be_bytes(), &self.master_key).unwrap();
|
||||
let encrypted_data = crypto::encrypt_data(&message.data, &self.master_key).unwrap();
|
||||
db.execute(&format!("INSERT INTO \"{}\" (outgoing, timestamp, data) VALUES (?1, ?2, ?3)", contact_uuid), params![encrypted_outgoing, encrypted_timestamp, encrypted_data]) |