webtrack-extension / src / background / core / Configuration.js
Configuration.js
Raw
import LocalstorageHandler from './LocalstorageHandler';


const LOAD_CERT_AFTER_SECONDS = 60*60*24;
// Every 20 minutes
const UPDATE_INTERVAL = 20*60*1000


export default class Configuration {

  /**
   * [constructor]
   * @param {Object} settings [instance of Settings]
   * @param {Object} transfer [instance of Transfer]
   */
  constructor(settings, transfer) {
    this.settings = settings;
    this.versionType = settings.versionType + ' (' + settings.getBrowser().name + '-' + settings.getBrowser().version + ')';
    this.mobile = settings.mobile;
    this.transfer = transfer;
    this.getProject = this.getProject.bind(this);
    this.getProjects = this.getProjects.bind(this);
    this.setSending = this.setSending.bind(this);
    this.load = this.load.bind(this);
    this.projectsStorage = new LocalstorageHandler('projects', null);
    this.select = new LocalstorageHandler('select', null);
    this.defaultId = new LocalstorageHandler('defaultId', null);
    this.certstorage = new LocalstorageHandler('cert', null);
    this.projectsTmpSettings = new LocalstorageHandler('projectsTmpSettings', {});
    this.is_load = false;
    this.debug = false;

  }


  /**
   * [initialize the default id]
   */
  initDefaultId(){
    if(this.defaultId.get()==null){
      let id = "";
      let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
      for (let i = 0; i < 10; i++) id += possible.charAt(Math.floor(Math.random() * possible.length));
      this.defaultId.set(id);
    }
  }


  /**
   * [_isTimeDiffover check is time over required seconds]
   * @param  {Number}  time
   * @param  {Number}  [seconds]
   * @return {Boolean}
   */
  _isTimeDiffover(time=0, seconds=0){
    return parseInt((new Date().getTime()-time)/1000, 10)> seconds;
  }

  /**
   * [_fetchCert load and save server-certificate]
   * @return {String} cert
   */
  _fetchCert(){
    return new Promise((resolve, reject)=>{
      let cert = this.certstorage.get();
      if(cert===null){
        //if (this.debug) console.log('No certificate, fetching one');
        this.transfer.fileFetch(this.settings.server+'tracking/cert').then(cert => {
          //if (this.debug) console.log('Fetch certificate!');
          this.certstorage.set(cert)
          resolve(true);
         })
        .catch(err => {
          //if (this.debug) console.log('Faile fetching the certificate: ', err);
          resolve(false);
        })
      }else{
        if(this._isTimeDiffover(this.certstorage.getTimestamp(), LOAD_CERT_AFTER_SECONDS)){
          //if (this.debug) console.log('Expired certificate, renewing it');
          this.certstorage.set(null)
          this._fetchCert().then(b => resolve(b));
        }else{
          //if (this.debug) console.log('Using restored certificate');
          resolve(true)
        }
      }
    });
  }

  /**
   * [getCert return all certificate]
   * @return {String}
   */
  getCert(){
    return this.cert
  }

  /**
   * [_fetchProject deliver all projects]
   * @return {Array}
   */
  _fetchProject(){
    return new Promise((resolve, reject)=>{

      let client_hash = null;
      if (this.getRunProjectTmpSettings()){
        client_hash = this.getRunProjectTmpSettings().clientId;
      } 
      if (client_hash == null ) {
        client_hash = 'NULL';
      }
      this.transfer.jsonFetch(this.settings.server+'client/getProjects', {
          method: 'POST',
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({client_hash: client_hash})})
      .then(projects => {
          //if (this.debug) console.log('Fetch projects!');
          this.projectsStorage.set(projects);
          this.store_projects(projects);
          resolve(true);
         })
        .catch(err => {
          //if (this.debug) console.log('_fetchProject: ', err);
          console.log("Failed fetching the projects");
          resolve(false);
        })

    });
  }

  /**
   * [getProjects return all projects]
   * @return {Array}
   */
  getProjects(){
    //if (this.debug) console.log('-> Configuration.getProjects()');
    return this.projects;
  }


  /**
   * [is the configuraion loaded correctly]
   * @return {Boolean} [true if the configuration was loaded correctly]
   */
  isLoaded(){
    //if (this.debug) console.log('-> Configuration.isLoaded()');
    return this.is_load;
  }

  /**
   * [getProject return project settings]
   * @param  {Integer} id
   * @return {Object}
   */
  getProject(id){
    if(this.isProjectAvailable(id)){
      return this.projects[this.projectIdtoIndex[id]]
    }else{
      return false;
    }    
  }


  isProjectAvailable(id){
    return this.projectIdtoIndex.hasOwnProperty(id);
  }

  /**
   * [_getProjectsTmpSettings return all user-settings of project]
   * @return {Object}
   */
  _getProjectsTmpSettings(){
    //if (this.debug) console.log('-> Configuration.getProjectSettings()');
    if (!this.isLoaded()){
      return {};
    }
    let newSettings = {};
    for (let p of this.projects) { 
      newSettings[p.ID] = {clientId: null, privateMode: false, sending: false}
    }
    let r = Object.assign({}, newSettings, this.projectsTmpSettings.get());
    for (let id in r) {
      if(!this.projectIds.includes(parseInt(id, 10))) { 
        delete r[id];
      }
    }
    this.projectsTmpSettings.set(r);
    return r;
  }

  /**
   * [setSelect set select id of project
   * if id null than client will be logout with his id]
   * @param {Integer} id
   */
  setSelect(id){
    //if (this.debug) console.log('-> Configuration.setSelect(',id,')');

    if(id==null){
      this.setProjectsTmpSettings({clientId: null});
      this.select.set(null);
    } else if (!this.isLoaded()){
      // Do not remove the client Id
      this.select.set(null);
    } else{
      id = parseInt(id, 10);
      if(this.projectIds.includes(id)) this.select.set(id);
    }
  }

  /**
   * [setProjectsTmpSettings set options of project]
   * @param {Object} setting [e.g. {privateMode: true, clientId: 'xcdy'}]
   */
  setProjectsTmpSettings(setting){
    //if (this.debug) console.log('-> Configuration.setProjectsTmpSettings()');

    let tmp = this.projectsTmpSettings.get();
    let project_settings = Object.assign({}, tmp[this.select.get()], setting);
    tmp[this.select.get()]= project_settings;
    this.projectsTmpSettings.set(tmp);
  }

  /**
   * [setPrivateMode set the private-mode of current project]
   * @param {Boolean} b
   */
  setPrivateMode(b){
    this.setProjectsTmpSettings({privateMode: b});
  }

  /**
   * [getProjectSettings return all settings from all projects]
   * @return {Object}
   */
  getProjectSettings(){
    //if (this.debug) console.log('-> Configuration.getProjectSettings()');
    return this._getProjectsTmpSettings();
  }

  /**
   * [getRunProjectSettings deliver active project settings]
   * @return {Object}
   */
  getRunProjectTmpSettings(){
    //if (this.debug) console.log('-> Configuration.getRunProjectTmpSettings()');
    let selected = this.getSelect();
    if(this._getProjectsTmpSettings().hasOwnProperty(selected)){
      return this._getProjectsTmpSettings()[selected];
    }
    return null;
  }

  /**
   * [setClientId set the clientid of current project]
   * @param {String} client_hash
   */
  setClientId(client_hash, project_id){
    return new Promise((resolve, reject)=>{
      //if (this.debug) console.log('-> config.setClientId(', client_hash, ',', project_id, ')');

      if (client_hash == null){
        this.setProjectsTmpSettings({clientId: null});
        resolve(true);
      } else {
        client_hash = client_hash.trim();
        if(this.projectIdtoIndex.hasOwnProperty(project_id) && 
          this.projects[this.projectIdtoIndex[project_id]].SETTINGS.ENTERID){
          if(this.projects[this.projectIdtoIndex[project_id]].SETTINGS.CHECK_CLIENTIDS){
              let options = {
                method: 'POST',
                headers:{
                  'Accept': 'application/json',
                  'Content-Type': 'application/json'
                },
                body: JSON.stringify({'client_hash': client_hash, 'project_id': project_id})
              };
              this.transfer.jsonFetch(this.settings.server+'client/checkid', options)
              .then(b => {
                if(b) this.setProjectsTmpSettings({clientId: client_hash});
                resolve(b)
               })
              .catch(err => {
                resolve(null);
              })
          }else{
            this.setProjectsTmpSettings({clientId: client_hash});
            resolve(true);
          }
        } else {
          reject('Set clientId is not necessary because project settings not required this setting')
        }
      }
    });
  }

  /**
   * [setPrivateMode set the clientid of current project]
   * @param {String} clientId
   */
  setSending(b=false){
    this.setProjectsTmpSettings({sending: b});
  }

  /**
   * [getSelect return selected project_id]
   * @return {Integer}
   */
  getSelect(){
    //if (this.debug) console.log('-> Configuration.getSelect()');
    let select = this.select.get();
    if (select == null) {
      let project_name = this.settings.project_name
      console.log(this.projects) 
      for (let index in this.projects) {
        if (this.projects[index].NAME == project_name) {
          select = this.projects[index].ID;
          break;
        }
      }
      if (select == null) {
        console.log('No project with the name:', project_name);
      } else {
        console.log('Project found: ', project_name);

      }
    }

    //if (this.debug) console.log('<- Configuration.getSelect()')
    return select;
  }

  /**
   * load the projects and variables associated for the main control of the prorgram
   * @param  projects coming from the server request
   */
  store_projects(projects){
    //if (this.debug) console.log('-> Configuration.store_projects()');
    this.projectIds = projects.map(v => v.ID);
    this.projectIdtoIndex = {}
    for (let index in projects) {
      this.projectIdtoIndex[projects[index].ID] = index;
    }
    this.projects = projects;
    
    let selected = this.getSelect();
    if(!this.is_load && !this.mobile && selected != null && this.isProjectAvailable(selected)){
      let p = this.projects[this.projectIdtoIndex[selected]];
      if(p.SETTINGS.ENTERID && p.SETTINGS.FORGOT_ID){
        this.setProjectsTmpSettings({clientId: null});
      }
      this.setProjectsTmpSettings({privateMode: false});
    }
    this.is_load = true;

    setTimeout(() => this.load(), UPDATE_INTERVAL);
    
  }

  /**
   * load dummy variables when the connection to the server is not succesful
   */
  _loadDisconnectedMode(){
    //if (this.debug) console.log('Operating in disconnected mode');

    this.projectIds = null;
    this.projectIdtoIndex = null;
    this.projects = [];
    setTimeout(() => this.load(), UPDATE_INTERVAL);

  }

  /**
   * [load // fetch all required settings from server]
   */
  load(){

    return new Promise(async (resolve, reject)=>{

      //if (this.debug) console.log('-> Configuration.load() - Promise');

      //TODO: is this necessary
      this.initDefaultId();

      // Load the certificates
      if (await this._fetchCert()){

        // Load the projects
        await this._fetchProject();
      }

      //if (this.debug) console.log('<- Configuration.load() - Promise');
      resolve(this.is_load);

    });//Promise
  }




}//class