You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			121 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			JavaScript
		
	
			
		
		
	
	
			121 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			JavaScript
		
	
/* global window, setTimeout, clearTimeout, textsecure, WebAPI, ConversationController */
 | 
						|
 | 
						|
module.exports = {
 | 
						|
  initialize,
 | 
						|
};
 | 
						|
 | 
						|
const ONE_DAY = 24 * 60 * 60 * 1000; // one day
 | 
						|
const MINIMUM_TIME_LEFT = 2 * 60 * 60 * 1000; // two hours
 | 
						|
 | 
						|
let timeout = null;
 | 
						|
let scheduledTime = null;
 | 
						|
let scheduleNext = null;
 | 
						|
 | 
						|
// We need to refresh our own profile regularly to account for newly-added devices which
 | 
						|
//   do not support unidentified delivery.
 | 
						|
function refreshOurProfile() {
 | 
						|
  const ourNumber = textsecure.storage.user.getNumber();
 | 
						|
  const conversation = ConversationController.getOrCreate(ourNumber, 'private');
 | 
						|
  conversation.getProfiles();
 | 
						|
}
 | 
						|
 | 
						|
function initialize({ events, storage, navigator, logger }) {
 | 
						|
  // We don't want to set up all of the below functions, but we do want to ensure that our
 | 
						|
  //   refresh timer is up-to-date.
 | 
						|
  if (scheduleNext) {
 | 
						|
    scheduleNext();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  runWhenOnline();
 | 
						|
 | 
						|
  events.on('timetravel', scheduleNextRotation);
 | 
						|
 | 
						|
  function scheduleNextRotation() {
 | 
						|
    const now = Date.now();
 | 
						|
    const certificate = storage.get('senderCertificate');
 | 
						|
    if (!certificate) {
 | 
						|
      setTimeoutForNextRun(now);
 | 
						|
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    // The useful information in a SenderCertificate is all serialized, so we
 | 
						|
    //   need to do another layer of decoding.
 | 
						|
    const decoded = textsecure.protobuf.SenderCertificate.Certificate.decode(
 | 
						|
      certificate.certificate
 | 
						|
    );
 | 
						|
    const expires = decoded.expires.toNumber();
 | 
						|
 | 
						|
    const time = Math.min(now + ONE_DAY, expires - MINIMUM_TIME_LEFT);
 | 
						|
 | 
						|
    setTimeoutForNextRun(time);
 | 
						|
  }
 | 
						|
 | 
						|
  // Keeping this entrypoint around so more inialize() calls just kick the timing
 | 
						|
  scheduleNext = scheduleNextRotation;
 | 
						|
 | 
						|
  async function run() {
 | 
						|
    logger.info('refreshSenderCertificate: Getting new certificate...');
 | 
						|
    try {
 | 
						|
      const username = storage.get('number_id');
 | 
						|
      const password = storage.get('password');
 | 
						|
      const server = WebAPI.connect({ username, password });
 | 
						|
 | 
						|
      const { certificate } = await server.getSenderCertificate();
 | 
						|
      const arrayBuffer = window.Signal.Crypto.base64ToArrayBuffer(certificate);
 | 
						|
      const decoded = textsecure.protobuf.SenderCertificate.decode(arrayBuffer);
 | 
						|
 | 
						|
      decoded.certificate = decoded.certificate.toArrayBuffer();
 | 
						|
      decoded.signature = decoded.signature.toArrayBuffer();
 | 
						|
      decoded.serialized = arrayBuffer;
 | 
						|
 | 
						|
      storage.put('senderCertificate', decoded);
 | 
						|
      scheduleNextRotation();
 | 
						|
    } catch (error) {
 | 
						|
      logger.error(
 | 
						|
        'refreshSenderCertificate: Get failed. Trying again in two minutes...',
 | 
						|
        error && error.stack ? error.stack : error
 | 
						|
      );
 | 
						|
      setTimeout(runWhenOnline, 2 * 60 * 1000);
 | 
						|
    }
 | 
						|
 | 
						|
    refreshOurProfile();
 | 
						|
  }
 | 
						|
 | 
						|
  function runWhenOnline() {
 | 
						|
    if (navigator.onLine) {
 | 
						|
      run();
 | 
						|
    } else {
 | 
						|
      logger.info(
 | 
						|
        'refreshSenderCertificate: Offline. Will update certificate when online...'
 | 
						|
      );
 | 
						|
      const listener = () => {
 | 
						|
        logger.info(
 | 
						|
          'refreshSenderCertificate: Online. Now updating certificate...'
 | 
						|
        );
 | 
						|
        window.removeEventListener('online', listener);
 | 
						|
        run();
 | 
						|
      };
 | 
						|
      window.addEventListener('online', listener);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  function setTimeoutForNextRun(time = Date.now()) {
 | 
						|
    const now = Date.now();
 | 
						|
 | 
						|
    if (scheduledTime !== time || !timeout) {
 | 
						|
      logger.info(
 | 
						|
        'Next sender certificate refresh scheduled for',
 | 
						|
        new Date(time).toISOString()
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    scheduledTime = time;
 | 
						|
    const waitTime = Math.max(0, time - now);
 | 
						|
 | 
						|
    clearTimeout(timeout);
 | 
						|
    timeout = setTimeout(runWhenOnline, waitTime);
 | 
						|
  }
 | 
						|
}
 |