| 
						
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -1,9 +1,10 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/* global log, textsecure, libloki, Signal */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/* global log, textsecure, libloki, Signal, Whisper */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				const EventEmitter = require('events');
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				const nodeFetch = require('node-fetch');
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				const { URL, URLSearchParams } = require('url');
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				const GROUPCHAT_POLL_EVERY = 1000; // 1 second
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				const DELETION_POLL_EVERY = 60000; // 1 minute
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// singleton to relay events to libtextsecure/message_receiver
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				class LokiPublicChatAPI extends EventEmitter {
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -174,6 +175,7 @@ class LokiPublicChannelAPI {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    log.info(`registered LokiPublicChannel ${channelId}`);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // start polling
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    this.pollForMessages();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    this.pollForDeletions();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  getEndpoint() {
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -206,20 +208,56 @@ class LokiPublicChannelAPI {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // read all messages from 0 to current
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // delete local copies if server state has changed to delete
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // run every minute
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const url = new URL(this.baseChannelUrl);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let res;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let success = true;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    try {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      res = await nodeFetch(url);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    } catch (e) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      success = false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const pollAgain = () => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      setTimeout(() => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        this.pollForDeletions();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }, DELETION_POLL_EVERY);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const response = await res.json();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (response.meta.code !== 200) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      success = false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let numChecked = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const url = new URL(`${this.baseChannelUrl}/messages`);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const params = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      include_annotations: 1,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      count: -200,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let beforeId = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    while (numChecked < 2000) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      params.before_id = beforeId;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      url.search = new URLSearchParams(params);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      let res;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      try {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // eslint-disable-next-line no-await-in-loop
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        res = await nodeFetch(url);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      } catch (e) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        pollAgain();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      // eslint-disable-next-line no-await-in-loop
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      const response = await res.json();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (response.meta.code !== 200) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        pollAgain();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      numChecked += response.data.length;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      // eslint-disable-next-line no-loop-func
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      response.data.reverse().forEach(adnMessage => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (beforeId === 0 || adnMessage.id < beforeId) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          beforeId = adnMessage.id;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (adnMessage.is_deleted) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          Whisper.events.trigger('deletePublicMessage', {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            messageServerId: adnMessage.id,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            conversationId: this.conversationId,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          });
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      });
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (response.data.length < 200) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return success;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    pollAgain();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  async pollForMessages() {
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -227,6 +265,7 @@ class LokiPublicChannelAPI {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const params = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      include_annotations: 1,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      count: -20,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      include_deleted: false,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (this.lastGot) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      params.since_id = this.lastGot;
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -264,6 +303,16 @@ class LokiPublicChannelAPI {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          ({ from, timestamp, source } = noteValue);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          !from ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          !timestamp ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          !source ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          !adnMessage.id ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          !adnMessage.text
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          return; // Invalid message
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        const messageData = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          serverId: adnMessage.id,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          friendRequest: false,
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
			
			 | 
			 | 
			
				
 
 |