From 1f7787ecf7dbc806e015b71cc2f6d494dc868e7b Mon Sep 17 00:00:00 2001 From: Beaudan Brown Date: Wed, 28 Aug 2019 17:15:44 +1000 Subject: [PATCH] Add token retrieval functions to public chat api --- js/background.js | 15 ++-- js/modules/loki_public_chat_api.js | 107 ++++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 13 deletions(-) diff --git a/js/background.js b/js/background.js index 141218b5f..a791a9ccc 100644 --- a/js/background.js +++ b/js/background.js @@ -224,18 +224,11 @@ ); publicConversations.forEach(conversation => { const settings = conversation.getPublicSource(); - window.log.info(`Setting up public conversation for ${conversation.id}`); - const publicChatServer = window.lokiPublicChatAPI.findOrCreateServer( - settings.server + window.lokiPublicChatAPI.registerChannel( + settings.server, + settings.channelId, + conversation.id ); - if (publicChatServer) { - publicChatServer.findOrCreateChannel( - settings.channelId, - conversation.id - ); - } else { - window.log.warn(`Could not set up channel for ${conversation.id}`); - } }); window.lokiP2pAPI = new window.LokiP2pAPI(ourKey); window.lokiP2pAPI.on('pingContact', pubKey => { diff --git a/js/modules/loki_public_chat_api.js b/js/modules/loki_public_chat_api.js index 1acc1e884..a31a9a3d9 100644 --- a/js/modules/loki_public_chat_api.js +++ b/js/modules/loki_public_chat_api.js @@ -1,4 +1,4 @@ -/* global log, textsecure */ +/* global log, textsecure, libloki, Signal */ const EventEmitter = require('events'); const nodeFetch = require('node-fetch'); const { URL, URLSearchParams } = require('url'); @@ -22,6 +22,10 @@ class LokiPublicChatAPI extends EventEmitter { } return thisServer; } + registerChannel(hostport, channelId, conversationId) { + const server = this.findOrCreateServer(hostport); + server.findOrCreateChannel(channelId, conversationId); + } unregisterChannel(hostport, channelId) { let thisServer; let i = 0; @@ -46,6 +50,9 @@ class LokiPublicServerAPI { this.chatAPI = chatAPI; this.server = hostport; this.channels = []; + this.tokenPending = false; + this.tokenPromise = null; + this.baseServerUrl = `https://${this.server}`; } findOrCreateChannel(channelId, conversationId) { let thisChannel = this.channels.find( @@ -72,13 +79,102 @@ class LokiPublicServerAPI { this.channels.splice(i, 1); thisChannel.stopPolling = true; } + + async getServerToken() { + let token = await Signal.Data.getPublicServerTokenByServerName(this.server); + if (!token) { + token = await this.getNewToken(); + if (token) { + await Signal.Data.savePublicServerToken({ + server: this.server, + token, + }); + } + } + return token; + } + + async getNewToken() { + if (!this.tokenPending) { + this.tokenPending = true; + this.tokenPromise = new Promise(async res => { + const token = await this.requestToken(); + if (!token) { + res(null); + return; + } + const registered = await this.submitToken(token); + if (!registered) { + res(null); + return; + } + res(token); + }); + } + const token = await this.tokenPromise; + this.tokenPending = false; + return token; + } + + async requestToken() { + const url = new URL(`${this.baseServerUrl}/loki/v1/get_challenge`); + const params = { + pubKey: this.chatAPI.ourKey, + }; + url.search = new URLSearchParams(params); + + let res; + try { + res = await nodeFetch(url); + } catch (e) { + return null; + } + if (!res.ok) { + return null; + } + const body = await res.json(); + const { cipherText64, serverPubKey64 } = body; + const token = await libloki.crypto.decryptToken( + cipherText64, + serverPubKey64 + ); + return token; + } + + async submitToken(token) { + const options = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + pubKey: this.chatAPI.ourKey, + token, + }), + }; + + let res; + let success = true; + try { + res = await nodeFetch( + `${this.baseServerUrl}/loki/v1/submit_challenge`, + options + ); + success = res.ok; + } catch (e) { + return false; + } + return success; + } } class LokiPublicChannelAPI { constructor(serverAPI, channelId, conversationId) { this.serverAPI = serverAPI; this.channelId = channelId; - this.baseChannelUrl = `${serverAPI.server}/channels/${this.channelId}`; + this.baseChannelUrl = `${serverAPI.baseServerUrl}/channels/${ + this.channelId + }`; this.groupName = 'unknown'; this.conversationId = conversationId; this.lastGot = 0; @@ -88,6 +184,13 @@ class LokiPublicChannelAPI { this.pollForMessages(); } + getEndpoint() { + const endpoint = `https://${this.serverAPI.server}/channels/${ + this.channelId + }/messages`; + return endpoint; + } + async pollForChannel(source, endpoint) { // groupName will be loaded from server const url = new URL(this.baseChannelUrl);