Installazione OrientDB su Debian

  1. ho scaricato e scompattato il tar.gz
  2. ho cambiato il nome e il gruppo di tutti i files in orientdb (già esistente)
  3. restringo i permessi ai file di configurazione:
    chmod 600 /path/orientdb/config
    chmod 600 /path/orientdb/config/orientdb-server-config.xml
  4. ho modificato orientdb-server-config.xml aggiungendo
    <entry value="/path/to/databases" name="server.database.path" >
  5. modifico anche i listeners (sempre in orientdb-server-config.xml)
  6. posso eliminare anche l’utente guest del server: da root entro nella console e posso vedere gli utenti attivi con list server users, e cancellare guest con drop server user guest
  7. posso modificare gli utenti di ogni singolo database (admin, writer, reader), anche da Studio
  8. eventualmente si può criptare il database con AES

riferimento: https://www.digitalocean.com/community/tutorials/how-to-secure-your-orientdb-database-on-ubuntu-16-04

Informazioni hardware con Windows e WMIC

https://docs.microsoft.com/it-IT/windows/desktop/wmisdk/wmic

per vedere cosa si può fare con WMIC, si può leggere l’help con il comando

wmic /?

tra gli altri, troviamo i seguenti ALIAS:

  • BASEBOARD: fornisce informazioni sulla scheda madre
  • BIOS: ….
  • BOOTCONFIG: configurazione di avvio
  • CPU: ….
  • MEMORYCHIP: informazioni sulla RAM
  • STARTUP: programmi eseguiti all’avvio

con GET è possibile selezionare, separati da virgole, i campi da visualizzare: ad esempio

wmic memorychip get manufacturer, partnumber, capacity

è possibile formattare l’output in vari formati: vedere l’help

wmic /FORMAT /?

pagina di manuale:
https://ss64.com/nt/wmic.html

Compilare CouchDB 2.3.0 su Debian Buster (testing)

Uso una macchina virtuale VirtualBox, su cui ho installato Debian Buster (testing) 64 bit, fresh.
Per comodità ho aggiunto LXDE.

  1. Installo make e build-essential
  2. Installo linux-headers-amd64
  3. Installo erlang

Dopo aver scaricato e scompattato apache-couchdb-2.3.0.tar.gz,entro nella directory e lancio i comandi ./configure e make: la compilazione si arresta perchè non viene trovato il file jsapi.h : questo perchè non è soddisfatta la dipendenza di Mozilla SpiderMonkey (1.8.5), ovvero il pacchetto libmozjs185-dev, non disponibile per Buster.

La cosa più semplice, per soddisfare le dipendenze di libmozjs185-dev è scaricare il pacchetto per una diversa release (sid ha solo la versione per arm64….. prendo la versione per Debian stretch): nella pagina https://packages.debian.org/stretch/libmozjs185-dev si vede che esso dipende a sua volta da libffi-dev e libnspr4-dev, che però sono disponibili per Buster e che quindi installo senza problemi da aptitude.

Invece libmozjs185-dev e libmozjs185-1.0 li scarico come file .deb e li installo con dpkg -i libmozjs185-*

Adesso manca la libreria libicu-dev, disponibile con aptitude.

Ora la compilazione viene eseguita senza errori.

Per creare la release da usare, si lancia il comando make release: questo crea la directory rel/couchdb che può essere copiata sul server, pronta per essere usata.

Ricapitolando: i pacchetti necessari per la compilazione sono:

  • make
  • build-essential
  • linux-headers-amd64
  • erlang
  • libffi-dev
  • libnspr4-dev
  • libicu-dev
  • libmozjs185-dev e libmozjs185-1.0 devono essere scaricati manualmente

Ora copio rel/couchdb in /opt e creo l’utente e il gruppo “couchdb”, e quindi cambio i permessi dei file (si può anche evitare di creare la home directory per questo user…. forse si può anche impostare il disabled-login…. da studiare):

adduser --system \
--shell /bin/bash \
--group --gecos \
"CouchDB Administrator" couchdb

chown -R couchdb:couchdb /opt/couchdb
find /opt/couchdb -type d -exec chmod 0770 {} \;
chmod 0644 /opt/couchdb/etc/*

# lancio couchdb come utente couchdb:
su - couchdb /opt/couchdb/bin/couchdb

anche se si vedono diversi messaggi di warning o errore, non importa: dobbiamo ancora configurare il server.
Puntanto il browser su localhost:5984 dobbiamo ricevere un messaggio JSON di benvenuto : l’installazione è avvenuta correttamente !!!

La configurazione e la verifica si effettuano sulle pagine:
http://127.0.0.1:5984/_utils/index.html
http://localhost:5984/_utils/index.html#verifyinstall

Ora rimane solo la creazione di uno script per lanciare couchdb con systemd:

[Unit]
Description=Couchdb service
After=network.target

[Service]
Type=simple
User=couchdb
Group=couchdb
ExecStart=/opt/couchdb/bin/couchdb -o /dev/stdout -e /dev/stderr
Restart=always

[Install]
WantedBy=multi-user.target

Per utilizzare couchdb compilato su altre macchine, è necessario installare la libreria libmozjs185-1.0 !!!!

Configurare il bind_address nella configurazione di rete, e impostare iptables di conseguenza.

FF WebExtension: messaging

di seguito pubblico una base per un progetto di WebExtension che utilizza il sistema di scambio di messaggi tra content script e background script.
mi rimane un dubbio: impostando “run_at” come nel seguente esempio

// manifest.json

{

"manifest_version": 2,
"name": "somename DEBUG",
"version": "1.0",

"applications": {
"gecko": {
"id": "myname@mydomain",
"strict_min_version": "54.0"
}
},

"icons": {
"56": "icons/icon_128x128.png"
},

"permissions": [
"tabs", "webRequest", "webRequestBlocking", "webNavigation", "*://*.someurl.com/*"
],

"background": {
"scripts": ["backgroundInclude.js", "background.js"]
},

"content_scripts": [{
"matches": ["*://*.someurl.com/*"],
"js": ["include.js", "main.js"],
"css": ["css/style.css"],
"run_at": "document_start"
}]
}

lo script viene iniettato prima che avvenga il caricamento del DOM.
ma chi mi garantisce che la connessione delle porte tra content script e background avvenga prima che possa essere effettuata qualche web request ?

la successione degli eventi è la seguente: quando il background intercetta una Web Request, la inoltra con un messaggio al content script

  1. BACKGROUND: costruttore
  2. BACKGROUND: onBeforeNavigate
  3. BACKGROUND: onCommitted
  4. CONTENT: constructor
  5. CONTENT: port connect to background
  6. BACKGROUND: port onConnect
  7. BACKGROUND: onBeforeRequest (xhr)
  8. BACKGROUND: onBeforeRequest (xhr)
  9. BACKGROUND: onBeforeRequest (xhr)
  10. CONTENT: xhr request received from background
  11. CONTENT: xhr request received from background
  12. CONTENT: xhr request received from background
  13. BACKGROUND: onDOMContentLoaded

sembrerebbe che la connessione delle porte avvenga prima che vengano effettuate le Web Request, ma ho provato ad inserire un setTimeout nel costruttore del content script e ho notato che le Web Request non attendono la restituzione del costruttore….

probabilmente bisogna interrompere il caricamento delle pagine per attendere la completa connessione delle porte ?

background script

notare il callback onDisconnect: viene lanciato quando la porta viene disconnessa dal content_script

'use strict';

class IGBackground {
constructor() {
console.log("BACKGROUND: costruttore");
this.ports = [];
this.urlFilter = {
url: [{hostSuffix: "someurl.com"}]
};

this.onConnect = this.onConnect.bind(this);
this.onMessage = this.onMessage.bind(this);
this.onDisconnect = this.onDisconnect.bind(this);
this.onBeforeNavigate = this.onBeforeNavigate.bind(this);
this.onCommitted = this.onCommitted.bind(this);
this.onDOMContentLoaded = this.onDOMContentLoaded.bind(this);

this.onBeforeFirstRequest = this.onBeforeFirstRequest.bind(this);
this.onBeforeGraphQLRequest = this.onBeforeGraphQLRequest.bind(this);

browser.runtime.onConnect.addListener(this.onConnect);
browser.webRequest.onBeforeRequest.addListener(this.onBeforeFirstRequest, {
urls: ["*://*.someurl.com/*"],
types: ["main_frame"]
}, ["blocking"]);
browser.webRequest.onBeforeRequest.addListener(this.onBeforeGraphQLRequest, {
urls: ["*://www.someurl.com/graphql/*"]
}, ["blocking"]);
browser.webNavigation.onBeforeNavigate.addListener(this.onBeforeNavigate, {
url: [{hostSuffix: "someurl.com"}]
});

browser.webNavigation.onCommitted.addListener(this.onCommitted, this.urlFilter);
browser.webNavigation.onDOMContentLoaded.addListener(this.onDOMContentLoaded, this.urlFilter);
}

onConnect(port) {
console.group("BACKGROUND");
console.log("port onConnect");
this.ports[port.sender.tab.id] = port;
this.ports[port.sender.tab.id].onMessage.addListener(this.onMessage);
this.ports[port.sender.tab.id].onDisconnect.addListener(this.onDisconnect);
console.log(this.ports);
console.groupEnd();
}

onMessage(msg) {
// riceve i messaggi dai content script
}

onDisconnect(port) {
console.log("BACKGROUND: port onDisconnect", port);
this.ports.splice(port.sender.tab.id, 1);
console.log("BACKGROUND: ports", this.ports);
}

onBeforeFirstRequest(details) {
console.group("BACKGROUND")
console.log("onBeforeFirstRequest");
console.log(details.url);
console.log(this.ports);
console.groupEnd();
return {};
}

onBeforeGraphQLRequest(details) {
console.log("BACKGROUND: onBeforeGraphQLRequest");
let filter = browser.webRequest.filterResponseData(details.requestId);
let decoder = new TextDecoder("utf-8");
let port = this.ports[details.tabId];
let data = "";

// filter.onstart = event => {}

filter.ondata = event => {
data += decoder.decode(event.data, {stream: true});
// inoltra i dati alla pagina HTML
filter.write(event.data);
}

filter.onstop = event => {
// TODO: controllare se tabId non è -1 (request no related to a tab)
// TODO: this.ports non è pronto subito ! è vuoto inizialmente
// TypeError: this.ports[details.tabId] is undefined
let json = JSON.parse(data);
json.address = decodeURIComponent(details.url);
port.postMessage(json);
filter.close();
}

filter.onerror = event => {
console.log(`Error: ${filter.error}`);
}
}

onBeforeNavigate(details) {
console.log("BACKGROUND: onBeforeNavigate");
}

onCommitted(details) {
console.log("BACKGROUND: onCommitted");
}

onDOMContentLoaded(details) {
console.log("BACKGROUND: onDOMContentLoaded");
}
}

content script

notare il callback onUnload: quando la pagina viene chiusa, disconnetto la porta, così il background, ricevendo l’evento onDisconnect, può fare pulizia.


'use strict';

class IG {
constructor() {
console.log("CONTENT: constructor");
this.port = browser.runtime.connect();
this.onMessage = this.onMessage.bind(this);
this.port.onMessage.addListener(this.onMessage);
console.log("CONTENT: port connected to background");

this.onUnload = this.onUnload.bind(this);
window.addEventListener("unload", this.onUnload);
}

onMessage(msg) {
console.log(msg);
}

onUnload(event) {
console.log("CONTENT: onunload");
this.port.disconnect();
}
}

Appunti: parser

function processText(testo) {
	var myArray = testo.split('\n');
	for(var i in myArray) {
		var re = /^(\d\d)\/(\d\d)\/(\d\d\d\d), (\d\d\:\d\d) - ([^:]*): (.*)/;
		var op = re.exec(myArray[i]);
		if(op) { console.log(re.exec(myArray[i]));}
		else { console.log(myArray[i]);}
	}
}

Leggere file locali con JavaScript

http://www.html5rocks.com/en/tutorials/file/dndfiles/?redirect_from_locale=it

Le specifiche forniscono diverse interfacce per accedere ai file locali:

  • File – an individual file; provides readonly information such as name, file size, mimetype, and a reference to the file handle. Riferimento MDN: File()
  • FileList – an array-like sequence of File objects. (Think or dragging a directory of files from the desktop). Riferimento MDN: FileList()
  • Blob – Allows for slicing a file into byte ranges.

Vedere inoltre i riferimenti MDN di: DataTransfer() e FileReader().
Usare file da web app: Tutorial MDN.

Verifica del supporto da parte del browser:

// Check for the various File API support.
if (window.File && window.FileReader && window.FileList && window.Blob) {
  // Great success! All the File APIs are supported.
} else {
  alert('The File APIs are not fully supported in this browser.');
}

Usare un form per scegliere i file:

<input type="file" id="files" name="files[]" multiple />
<output id="list"></output>

<script>
  function handleFileSelect(evt) {
    var files = evt.target.files; // FileList object

    // files is a FileList of File objects. List some properties.
    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
      output.push('<li><strong>', escape(f.name), '</strong> (',
                   f.type || 'n/a', ') - ', f.size, ' bytes,
                   last modified: ', f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
                  '</li>');
    }
    document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
  }
document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>

Usare il drag&drop:

<div id="drop_zone">Drop files here</div>
<output id="list"></output>
<script>
  function handleFileSelect(evt) {
    evt.stopPropagation();
    evt.preventDefault();

    var files = evt.dataTransfer.files; // FileList object.

    // files is a FileList of File objects. List some properties.
    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
      output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
                  f.size, ' bytes, last modified: ',
                  f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
                  '</li>');
    }
    document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
  }

  function handleDragOver(evt) {
    evt.stopPropagation();
    evt.preventDefault();
    evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
  }

  // Setup the dnd listeners.
  var dropZone = document.getElementById('drop_zone');
  dropZone.addEventListener('dragover', handleDragOver, false);
  dropZone.addEventListener('drop', handleFileSelect, false);
</script>

In entrambi i casi si ottiene una FileList() di oggetti File().
Con FileReader() si può leggere un file:

  • FileReader.readAsBinaryString(Blob|File) – The result property will contain the file/blob’s data as a binary string. Every byte is represented by an integer in the range [0..255].
  • FileReader.readAsText(Blob|File, opt_encoding) – The result property will contain the file/blob’s data as a text string. By default the string is decoded as ‘UTF-8’. Use the optional encoding parameter can specify a different format.
  • FileReader.readAsDataURL(Blob|File) – The result property will contain the file/blob’s data encoded as a data URL.
  • FileReader.readAsArrayBuffer(Blob|File) – The result property will contain the file/blob’s data as an ArrayBuffer object.

Chiamando questi metodi, si ottiene una lettura asincrona, con gli eventi onloadstart, onprogress, onload, onabort, onerror, e onloadend.

Esempio: carichiamo immagini da una selezione utente, chiamiamo reader.readAsDataURL() sulle immagini, disegniamo una thumbnail usando l’ attributo ‘src’ con la URL.

<style>
  .thumb {
    height: 75px;
    border: 1px solid #000;
    margin: 10px 5px 0 0;
  }
</style>

<input type="file" id="files" name="files[]" multiple />
<output id="list"></output>

<script>
  function handleFileSelect(evt) {
    var files = evt.target.files; // FileList object

    // Loop through the FileList and render image files as thumbnails.
    for (var i = 0, f; f = files[i]; i++) {

      // Only process image files.
      if (!f.type.match('image.*')) {
        continue;
      }

      var reader = new FileReader();

      // Closure to capture the file information.
      reader.onload = (function(theFile) {
        return function(e) {
          // Render thumbnail.
          var span = document.createElement('span');
          span.innerHTML = ['<img class="thumb" src="', e.target.result, '" title="', escape(theFile.name), '"/>'].join('');
          document.getElementById('list').insertBefore(span, null);
        };
      })(f);

      // Read in the image file as a data URL.
      reader.readAsDataURL(f);
    }
  }

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>

Slicing a file

File() permette di leggere range di byte:

var blob = file.slice(startingByte, endindByte);
reader.readAsBinaryString(blob);

Esempio: notare che si usa onloadend e si controlla evt.target.readyState

<style>
  #byte_content {
    margin: 5px 0;
    max-height: 100px;
    overflow-y: auto;
    overflow-x: hidden;
  }
  #byte_range { margin-top: 5px; }
</style>

<input type="file" id="files" name="file" /> Read bytes: 
<span class="readBytesButtons">
  <button data-startbyte="0" data-endbyte="4">1-5</button>
  <button data-startbyte="5" data-endbyte="14">6-15</button>
  <button data-startbyte="6" data-endbyte="7">7-8</button>
  <button>entire file</button>
</span>

<div id="byte_range"></div>
<div id="byte_content"></div>

<script>
  function readBlob(opt_startByte, opt_stopByte) {

    var files = document.getElementById('files').files;
    if (!files.length) {
      alert('Please select a file!');
      return;
    }

    var file = files[0];
    var start = parseInt(opt_startByte) || 0;
    var stop = parseInt(opt_stopByte) || file.size - 1;

    var reader = new FileReader();

    // If we use onloadend, we need to check the readyState.
    reader.onloadend = function(evt) {
      if (evt.target.readyState == FileReader.DONE) { // DONE == 2
        document.getElementById('byte_content').textContent = evt.target.result;
        document.getElementById('byte_range').textContent = 
            ['Read bytes: ', start + 1, ' - ', stop + 1,
             ' of ', file.size, ' byte file'].join('');
      }
    };

    var blob = file.slice(start, stop + 1);
    reader.readAsBinaryString(blob);
  }
  
  document.querySelector('.readBytesButtons').addEventListener('click', function(evt) {
    if (evt.target.tagName.toLowerCase() == 'button') {
      var startByte = evt.target.getAttribute('data-startbyte');
      var endByte = evt.target.getAttribute('data-endbyte');
      readBlob(startByte, endByte);
    }
  }, false);
</script>

Monitorare il processo di lettura

Si usano gli eventi onloadstart e onprogress.
Esempio: barra di progressione

<style>
  #progress_bar {
    margin: 10px 0;
    padding: 3px;
    border: 1px solid #000;
    font-size: 14px;
    clear: both;
    opacity: 0;
    -moz-transition: opacity 1s linear;
    -o-transition: opacity 1s linear;
    -webkit-transition: opacity 1s linear;
  }
  #progress_bar.loading {
    opacity: 1.0;
  }
  #progress_bar .percent {
    background-color: #99ccff;
    height: auto;
    width: 0;
  }
</style>

<input type="file" id="files" name="file" />
<button onclick="abortRead();">Cancel read</button>

<div id="progress_bar">
<div class="percent">0%</div>
</div>

<script>
  var reader;
  var progress = document.querySelector('.percent');

  function abortRead() {
    reader.abort();
  }

  function errorHandler(evt) {
    switch(evt.target.error.code) {
      case evt.target.error.NOT_FOUND_ERR:
        alert('File Not Found!');
        break;
      case evt.target.error.NOT_READABLE_ERR:
        alert('File is not readable');
        break;
      case evt.target.error.ABORT_ERR:
        break; // noop
      default:
        alert('An error occurred reading this file.');
    };
  }

  function updateProgress(evt) {
    // evt is an ProgressEvent.
    if (evt.lengthComputable) {
      var percentLoaded = Math.round((evt.loaded / evt.total) * 100);
      // Increase the progress bar length.
      if (percentLoaded < 100) {
        progress.style.width = percentLoaded + '%';
        progress.textContent = percentLoaded + '%';
      }
    }
  }

  function handleFileSelect(evt) {
    // Reset progress indicator on new file selection.
    progress.style.width = '0%';
    progress.textContent = '0%';

    reader = new FileReader();
    reader.onerror = errorHandler;
    reader.onprogress = updateProgress;
    reader.onabort = function(e) {
      alert('File read cancelled');
    };
    reader.onloadstart = function(e) {
      document.getElementById('progress_bar').className = 'loading';
    };
    reader.onload = function(e) {
      // Ensure that the progress bar displays 100% at the end.
      progress.style.width = '100%';
      progress.textContent = '100%';
      setTimeout("document.getElementById('progress_bar').className='';", 2000);
    }

    // Read in the image file as a binary string.
    reader.readAsBinaryString(evt.target.files[0]);
  }

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>