Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. @@ -112,6 +112,8 @@
  2. return elem.value;
  3. } else if (elem = form_elem.querySelector('textarea[name=' + field_name + ']')) {
  4. return elem.value;
  5. + } else if (elem = form_elem.querySelector('select[name=' + field_name + ']')) {
  6. + return elem.value;
  7. }
  8. if (not_found_value !== undefined)
  9. return not_found_value;
  10. @@ -167,8 +169,11 @@
  11. cache_id_to_group_key_i32a : { }, // str to key
  12. msg_sound : null,
  13. user_pid : null,
  14. - cur_chat_other_user_pid : null,
  15. + cur_chat_other_user_pids : [],
  16. cur_chat_group_pid : null,
  17. + // Service chat
  18. + cur_chat_agent_service_pid : null,
  19. + cur_chat_agent_user_pids : [], // Which users in current chat are service agents
  20. };
  21.  
  22. const tmp_id = function()
  23. @@ -587,6 +592,7 @@
  24. };
  25.  
  26. const KV_STORE_KEY_CHAT_STATUS = 0;
  27. +const KV_STORE_KEY_SELF_ATTRIBUTES = 1;
  28.  
  29. const handle_new_post_response = function(values)
  30. {
  31. @@ -630,7 +636,11 @@
  32. let stored_object = null;
  33. if (kv.key === KV_STORE_KEY_CHAT_STATUS) {
  34. let content = u8a_to_str(i32a_to_u8a(decrypt_content_to_i32a(master_key_i32a(), u8a_to_i32a(b64_to_u8a(kv.value_ec_b64)))));
  35. - //console.log('chat_status', content);
  36. + stored_object = JSON.parse(content);
  37. + }
  38. +
  39. + if (kv.key === KV_STORE_KEY_SELF_ATTRIBUTES) {
  40. + let content = u8a_to_str(i32a_to_u8a(decrypt_content_to_i32a(master_key_i32a(), u8a_to_i32a(b64_to_u8a(kv.value_ec_b64)))));
  41. stored_object = JSON.parse(content);
  42. }
  43.  
  44. @@ -752,7 +762,7 @@
  45. t: 'div', classes: 'popup',
  46. });
  47.  
  48. - // TODO: Wrap elem is useless now (?)
  49. + // TODO: Wrap elem is useless now
  50. let wrap_elem = create_elem_tree({ t: 'div', classes: 'popup_wrap' });
  51. wrap_elem.appendChild(elem);
  52. g_some.open_popups.push({
  53. @@ -1423,8 +1433,7 @@
  54. return ret;
  55. };
  56.  
  57. -// For RSA key generation that has crappy api
  58. -// TODO: Make sure that rsa key-pair is generated from random data!
  59. +// For RSA key generation that has weird api
  60. function SecureRandom() {}
  61. SecureRandom.prototype.nextBytes = function(ba)
  62. {
  63. @@ -1590,6 +1599,25 @@
  64. }
  65. };
  66.  
  67. +const post_login = function(email, pw, callback)
  68. +{
  69. + let server_pass = pw;
  70. + let pass_key_i32a = null;
  71. + {
  72. + let derived_pair = password_to_key_i32a_and_str(pw);
  73. + pass_key_i32a = derived_pair[0];
  74. + server_pass = derived_pair[1];
  75. + }
  76. +
  77. + basic_data_post('/login', obj_to_uri({ email: email, password: server_pass }), function(success, info)
  78. + {
  79. + if (success && pass_key_i32a)
  80. + window.localStorage.setItem('pass_key', pass_key_i32a); // For decrypting mkey at next page
  81. +
  82. + callback(success, info);
  83. + });
  84. +};
  85. +
  86. const submit_login = function(evt)
  87. {
  88. let form = evt.target;
  89. @@ -1600,15 +1628,7 @@
  90. button.disabled = true;
  91.  
  92. clear_local_session_data(function() {
  93. - let server_pass = pw;
  94. - let pass_key_i32a = null;
  95. - {
  96. - let derived_pair = password_to_key_i32a_and_str(pw);
  97. - pass_key_i32a = derived_pair[0];
  98. - server_pass = derived_pair[1];
  99. - }
  100. -
  101. - basic_data_post('/login', obj_to_uri({ email: email, password: server_pass }), function(success, info)
  102. + post_login(email, pw, function(success, info)
  103. {
  104. if (!success) {
  105. show_page_notification(info);
  106. @@ -1616,8 +1636,6 @@
  107. return;
  108. }
  109.  
  110. - if (pass_key_i32a)
  111. - window.localStorage.setItem('pass_key', pass_key_i32a); // For decrypting mkey at next page
  112. window.location.href = '/welcome';
  113. });
  114. });
  115. @@ -1646,63 +1664,127 @@
  116. window.sessionStorage.setItem('page_notification', msg);
  117. };
  118.  
  119. -const submit_register_user = function(evt)
  120. +const try_generate_user_registration_info = function(inputs)
  121. {
  122. - let form = evt.target;
  123. - let display_name = form_field_value(form, 'display_name');
  124. - let email = form_field_value(form, 'email');
  125. - let password = form_field_value(form, 'password');
  126. - let password2 = form_field_value(form, 'password2');
  127. - let additional_info = form_field_value(form, 'additional_info');
  128. - let token = form_field_value(form, 'token');
  129. - let lang_id = form_field_value(form, 'lang_id');
  130. - let legal_text_id = form_field_value(form, 'legal_text_id');
  131. - let legal_consent = form_field_value(form, 'legal_consent');
  132. -
  133. - if (password != password2) {
  134. + if (inputs.password != inputs.password2) {
  135. show_page_notification(translated('Passwords do not match'));
  136. return;
  137. }
  138. - if (password.length <= 10) {
  139. + if (inputs.password.length <= 10) {
  140. show_page_notification(translated('Password too short'));
  141. return;
  142. }
  143. - if (legal_consent != 'on') {
  144. + if (inputs.legal_consent != 'on') {
  145. show_page_notification(translated('You have not accepted the terms and conditions'));
  146. return;
  147. }
  148.  
  149. // Always create also crypto user
  150. - let crypto = generate_crypto_credentials(password);
  151. + let crypto = generate_crypto_credentials(inputs.password);
  152. assert(crypto.server_pw);
  153. assert(crypto.mkey_ec_b64);
  154. assert(crypto.rsa_modulus_hex);
  155. assert(crypto.rsa_private_ec_b64);
  156. assert(crypto.rating_key_ec_b64);
  157.  
  158. + return {
  159. + create_also_crypto_user: 'on',
  160. +
  161. + display_name: inputs.display_name,
  162. + email: inputs.email,
  163. + additional_info: inputs.additional_info,
  164. + token: inputs.token,
  165. + lang_id: inputs.lang_id,
  166. + legal_text_id: inputs.legal_text_id,
  167. + legal_consent: inputs.legal_consent,
  168. +
  169. + preferred_agent: inputs.preferred_agent,
  170. +
  171. + password: crypto.server_pw,
  172. + password2: crypto.server_pw,
  173. + mkey_ec_b64: crypto.mkey_ec_b64,
  174. + rsa_modulus_hex: crypto.rsa_modulus_hex,
  175. + rsa_private_ec_b64: crypto.rsa_private_ec_b64,
  176. + rating_key_ec_b64: crypto.rating_key_ec_b64,
  177. + };
  178. +};
  179. +
  180. +const submit_register_user = function(evt)
  181. +{
  182. + let form = evt.target;
  183. + const form_inputs = {
  184. + display_name: form_field_value(form, 'display_name'),
  185. + email: form_field_value(form, 'email'),
  186. + password: form_field_value(form, 'password'),
  187. + password2: form_field_value(form, 'password2'),
  188. + additional_info: form_field_value(form, 'additional_info'),
  189. + token: form_field_value(form, 'token'),
  190. + lang_id: form_field_value(form, 'lang_id'),
  191. + legal_text_id: form_field_value(form, 'legal_text_id'),
  192. + legal_consent: form_field_value(form, 'legal_consent'),
  193. + };
  194. +
  195. + const user_registration_info = try_generate_user_registration_info(form_inputs);
  196. + if (!user_registration_info)
  197. + return;
  198. +
  199. basic_data_post('/register_user',
  200. - obj_to_uri({
  201. - create_also_crypto_user: 'on',
  202. + obj_to_uri(user_registration_info),
  203. + function(success, info, values)
  204. + {
  205. + if (success) {
  206. + post_login(form_inputs.email, form_inputs.password, function(success, info)
  207. + {
  208. + if (success)
  209. + window.location.href = '/';
  210. + else
  211. + show_page_notification(info);
  212. + });
  213. + } else {
  214. + show_page_notification(info);
  215. + }
  216. + }
  217. + );
  218. +};
  219.  
  220. - display_name: display_name,
  221. - email: email,
  222. - password: crypto.server_pw,
  223. - password2: crypto.server_pw,
  224. - additional_info: additional_info,
  225. - token: token,
  226. - lang_id: lang_id,
  227. - legal_text_id: legal_text_id,
  228. - legal_consent: legal_consent,
  229. -
  230. - mkey_ec_b64: crypto.mkey_ec_b64,
  231. - rsa_modulus_hex: crypto.rsa_modulus_hex,
  232. - rsa_private_ec_b64: crypto.rsa_private_ec_b64,
  233. - rating_key_ec_b64: crypto.rating_key_ec_b64
  234. - }),
  235. +const submit_register_to_agent_service = function(evt)
  236. +{
  237. + let form = evt.target;
  238. + const form_inputs = {
  239. + //gender: form_field_value(form, 'gender'),
  240. + //birthyear: form_field_value(form, 'birthyear'),
  241. + display_name: form_field_value(form, 'display_name'),
  242. + email: form_field_value(form, 'email'),
  243. + password: form_field_value(form, 'password'),
  244. + password2: form_field_value(form, 'password2'),
  245. + lang_id: form_field_value(form, 'lang_id'),
  246. + legal_text_id: form_field_value(form, 'legal_text_id'),
  247. + legal_consent: form_field_value(form, 'legal_consent'),
  248. + additional_info: '',
  249. + token: '',
  250. +
  251. + preferred_agent: form_field_value(form, 'preferred_agent')
  252. + };
  253. +
  254. + assert(form_inputs.preferred_agent);
  255. +
  256. + const user_registration_info = try_generate_user_registration_info(form_inputs);
  257. +
  258. + if (!user_registration_info)
  259. + return;
  260. +
  261. + basic_data_post('/register_user',
  262. + obj_to_uri(user_registration_info),
  263. function(success, info, values)
  264. {
  265. if (success) {
  266. - window.location.href = '/registration_complete';
  267. + post_login(form_inputs.email, form_inputs.password, function(success, info)
  268. + {
  269. + if (success)
  270. + window.location.href = '/';
  271. + else
  272. + show_page_notification(info);
  273. + });
  274. } else {
  275. show_page_notification(info);
  276. }
  277. @@ -1891,6 +1973,83 @@
  278. });
  279. };
  280.  
  281. +// Create and open chat between two users
  282. +const submit_open_chat = function(evt)
  283. +{
  284. + const form = evt.target;
  285. + const other_user_pid = form_field_value(form, 'other_user_pid');
  286. + const other_rsa_modulus_hex = form_field_value(form, 'other_rsa_modulus_hex');
  287. +
  288. + assert(sjcl.random.isReady(ENTROPY_PARANOIA));
  289. + assert(other_rsa_modulus_hex);
  290. + const key_i32a = sjcl.random.randomWords(4);
  291. + const key_ec_hex = rsa_encrypt_i32a_to_hex(rsa_public_key(), key_i32a);
  292. + const other_key_ec_hex = rsa_encrypt_i32a_to_hex(make_rsa_public_key(other_rsa_modulus_hex), key_i32a);
  293. +
  294. + basic_data_post('/create_chat',
  295. + obj_to_uri({
  296. + key_ec_hex: key_ec_hex,
  297. + other_user_pid: other_user_pid,
  298. + other_key_ec_hex: other_key_ec_hex
  299. + }),
  300. + function(success, info, values)
  301. + {
  302. + if (!success) {
  303. + show_page_notification(info);
  304. + return;
  305. + }
  306. +
  307. + const group_pid = values[0];
  308. + assert(group_pid);
  309. + document.location = '/chats/' + group_pid;
  310. + }
  311. + );
  312. +};
  313. +// Create and open chat between specific service agents and a user
  314. +const submit_open_agent_chat = function(evt)
  315. +{
  316. + const form = evt.target;
  317. + const agent_service_pid = form_field_value(form, 'agent_service_pid');
  318. + const other_users_psv = form_field_value(form, 'other_users');
  319. + const other_users_schema = [
  320. + { type: 'array', name: 'array', schema: [
  321. + 'pid', 'rsa_modulus_hex'
  322. + ]
  323. + },
  324. + ];
  325. + const other_users = array_to_obj(other_users_schema, psv_to_array(other_users_psv)).array;
  326. +
  327. + assert(sjcl.random.isReady(ENTROPY_PARANOIA));
  328. + const key_i32a = sjcl.random.randomWords(4);
  329. + const key_ec_hex = rsa_encrypt_i32a_to_hex(rsa_public_key(), key_i32a);
  330. +
  331. + // TODO: psv writing utils
  332. + let return_data = '' + other_users.length;
  333. + for (let i = 0; i < other_users.length; ++i) {
  334. + return_data += '|' + other_users[i].pid;
  335. + return_data += '|' + rsa_encrypt_i32a_to_hex(make_rsa_public_key(other_users[i].rsa_modulus_hex), key_i32a);
  336. + }
  337. +
  338. + basic_data_post('/create_agent_chat',
  339. + obj_to_uri({
  340. + agent_service_pid: agent_service_pid,
  341. + key_ec_hex: key_ec_hex,
  342. + other_users_psv: return_data,
  343. + }),
  344. + function(success, info, values)
  345. + {
  346. + if (!success) {
  347. + show_page_notification(info);
  348. + return;
  349. + }
  350. +
  351. + const group_pid = values[0];
  352. + assert(group_pid);
  353. + document.location = '/agent_chats/' + group_pid;
  354. + }
  355. + );
  356. +};
  357. +
  358. // Preprocess post src
  359. const upload_blobs_from_post = function(str, on_finished)
  360. {
  361. @@ -2866,7 +3025,6 @@
  362. { type: 'array', name: 'posts', schema: post_schema },
  363. ];
  364. const obj = array_to_obj(schema, parts);
  365. -
  366. const group_pid = html_encoded(obj.group_pid);
  367.  
  368. query_group_key_i32a(group_pid, function(group_key_i32a) // TODO: Store group key to 'decrypted_groups' instead of always requerying
  369. @@ -2927,6 +3085,7 @@
  370. {
  371. let chat_elem = $(this);
  372. let msgs_elem = $('#chat_msgs');
  373. +
  374. if (!msgs_elem.length) {
  375. is_first_time = true;
  376. chat_elem.append(create_elem_tree(
  377. @@ -2935,13 +3094,13 @@
  378. text: translated('Chat, ') + chat_elem.data('other_user_name')
  379. }
  380. ));
  381. - msgs_elem = $('<div id="chat_msgs"></div>');
  382. + msgs_elem = $(create_elem_tree({ t: 'div', id: 'chat_msgs' }));
  383. chat_elem.append(msgs_elem);
  384. }
  385. let got_new_msg_from_other = false;
  386. - let other_user_pid = chat_elem.data('other_user_pid') + '';
  387. + let elem_group_pid = chat_elem.data('group_pid') + '';
  388.  
  389. - if (last_msg_author_pid === g_some.user_pid || last_msg_author_pid === other_user_pid) { // TODO: Use group id to filter messages
  390. + if (elem_group_pid === group_pid) {
  391. for (let i = 0; i < new_elems.length; ++i)
  392. msgs_elem.append(new_elems[i]);
  393. }
  394. @@ -2951,6 +3110,7 @@
  395.  
  396. if (is_first_time) {
  397. chat_elem.append($(
  398. + // TODO: Use create_elem_tree
  399. '<form id="chat_msg_form" class="form">'
  400. +'<input type="hidden" name="group_pid" value="' + group_pid + '" />'
  401. +'<input type="hidden" name="visibility" value="' + POST_VISIBILITY_DEFAULT + '" />'
  402. @@ -2980,7 +3140,7 @@
  403. } else {
  404. try_play_sound(g_some.msg_sound, 0.3);
  405. // Using service workers now
  406. - //try_show_desktop_notification(translated('New message: ') + last_other_msg_author_name, '/chats/' + last_other_msg_author_pid);
  407. + //try_show_desktop_notification(translated('New message: ') + last_other_msg_author_name, '/chats/' + group_pid);
  408. }
  409.  
  410. update_notifications();
  411. @@ -3491,6 +3651,8 @@
  412. } else if (item.kind === 'string' && item.type === 'text/plain') {
  413. item.getAsString(function(s)
  414. {
  415. + wysiwyg_add_code(editor_id, s);
  416. +
  417. let found_urls = find_and_classify_urls(s);
  418. for (let i = 0; i < found_urls.length; ++i) {
  419. if (found_urls[i].embed_instruction) { // E.g. video embeds to external sites
  420. @@ -3783,6 +3945,8 @@
  421. submit_login(evt);
  422. } else if (tag === 'register_user') {
  423. submit_register_user(evt);
  424. + } else if (tag === 'register_to_agent_service') {
  425. + submit_register_to_agent_service(evt);
  426. } else if (tag === 'change_password') {
  427. submit_change_password(evt);
  428. } else if (tag === 'reset_password_and_crypto') {
  429. @@ -3793,6 +3957,10 @@
  430. submit_destroy_post(evt);
  431. } else if (tag === 'accept_encryted_group_member') {
  432. submit_accept_encryted_group_member(evt);
  433. + } else if (tag === 'open_chat') {
  434. + submit_open_chat(evt);
  435. + } else if (tag === 'open_agent_chat') {
  436. + submit_open_agent_chat(evt);
  437. } else if (tag === 'emulated') {
  438. // Normal html form converted to js form with minimal effort
  439. let form = evt.target;
  440. @@ -4070,35 +4238,28 @@
  441. {
  442. let chat_elem = $(this);
  443. assert(master_key_i32a());
  444. - g_some.cur_chat_other_user_pid = chat_elem.data('other_user_pid') + '';
  445. + g_some.cur_chat_other_user_pids = psv_to_array(chat_elem.data('other_user_pids'));
  446. g_some.cur_chat_group_pid = chat_elem.data('group_pid') + '';
  447. +
  448. + if (chat_elem.data('agent_service_pid')) {
  449. + g_some.cur_chat_agent_service_pid = chat_elem.data('agent_service_pid');
  450. + g_some.cur_chat_agent_user_pids = psv_to_array(chat_elem.data('other_agent_user_pids'));
  451. + }
  452. +
  453. let key_i32a;
  454. let key_ec_hex = chat_elem.data('key_ec_hex');
  455. let other_rsa_modulus_hex = chat_elem.data('other_rsa_modulus_hex');
  456. if (!other_rsa_modulus_hex || other_rsa_modulus_hex.length === 0) {
  457. chat_elem.html('<p>' + translated('Encrypted messaging is not possible because of the other party') + '</p>');
  458. } else {
  459. - if (!g_some.cur_chat_group_pid) { // Create chat group
  460. - assert(sjcl.random.isReady(ENTROPY_PARANOIA));
  461. - assert(other_rsa_modulus_hex);
  462. - key_i32a = sjcl.random.randomWords(4);
  463. - key_ec_hex = rsa_encrypt_i32a_to_hex(rsa_public_key(), key_i32a);
  464. - let other_key_ec_hex = rsa_encrypt_i32a_to_hex(make_rsa_public_key(other_rsa_modulus_hex), key_i32a);
  465. - // TODO: Pipe-separated values as standard
  466. - const send_cmd = 'create_chat\0' + key_ec_hex + '\0' + g_some.cur_chat_other_user_pid + '\0' + other_key_ec_hex;
  467. - send(send_cmd);
  468. - } else {
  469. - assert(key_ec_hex);
  470. - key_i32a = rsa_decrypt_hex_to_i32a(rsa_private_key(), key_ec_hex);
  471. - on_msg_chat_content(psv_to_array(chat_elem.data('chat_content')));
  472. - }
  473. + assert(key_ec_hex);
  474. + key_i32a = rsa_decrypt_hex_to_i32a(rsa_private_key(), key_ec_hex);
  475. assert(key_i32a && key_i32a.length == 4);
  476. + on_msg_chat_content(psv_to_array(chat_elem.data('chat_content')));
  477. }
  478. });
  479.  
  480. - if (g_some.is_verified)
  481. - init_websocket();
  482. -
  483. + init_websocket();
  484.  
  485. let rating_symbol = function(rating)
  486. {
  487. @@ -4317,8 +4478,8 @@
  488. g_some.push_sub_p256dh_b64u = script_init.push_sub_p256dh_b64u || null;
  489. g_some.push_sub_auth_b64u = script_init.push_sub_auth_b64u || null;
  490. g_some.user_pid = script_init.user_pid || null;
  491. - g_some.has_crypto_user = script_init.has_crypto;
  492. - g_some.is_verified = script_init.is_verified;
  493. + g_some.has_crypto_user = (script_init.has_crypto === '1');
  494. + g_some.is_verified = (script_init.is_verified === '1');
  495. g_some.bridge_origin = script_init.bridge_origin;
  496. g_some.script_init_data = script_init.data;
  497.  
  498.