// pour "configurer" le lecteur nfc
// ouvrir le fichier: sudo nano /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist (pour pi)
// localiser la ligne ifdDriverOptions,
// la ligne suivante vaux 0x0000,
// modifier la 0x0001,
// sauvegarder le fichier et redémarer pcscd(sudo service pcscd restart)
// même action pour le fichier sudo nano /usr/lib/pcsc/drivers/ifd-acsccid.bundle/Contents/Info.plist (pour desktop)
let script, ip, memSudoMdp = '', etatUrl = 0
let TAB = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '!', '#', '$', '%', '&', '?','0','1','2','3','4','5','6','7','8','9'];
let max_TAB = TAB.length - 1
let donneesFichierConfiguration = {}
// type de lecteur nfc
const typeLecteurNfc = 'vma405'
// dev = 1 = mode développement
let dev = 1
// nfc
const vma405Emitter = require('./vma405.js')
const os = require('os')
const hostname= os.hostname()
const { spawn, exec } = require('child_process')
const IP = require('ip')
const path = require('path')
const fs = require('fs')
// serveur http
const http = require('http')
// const ADR = '192.168.1.32'
const ADR = '127.0.0.1'
const PORT = 3000
const TOKEN = '$a;b2yuM5454@4!cd'
// retour = null = aucune demande de lecture de carte nfc
let retour = null
let client_globale = null
let fichier = '', contentType = ''
/**
* retourne l'ip
* @param {string|'public'|'private'} typeReseau
* @param {String|'ipv4'|'ipv6'} famille
* @returns {string}
*/
function obtenirIp(typeReseau, famille){
ip = IP.address(typeReseau, famille)
let retour = "erreur"
if (ip !== "127.0.0.1" && ip !== "0.0.0.0") {
retour = ip
}
return retour
}
// --- nfc ---
vma405Emitter.on('tagId', (tagId) => {
if (retour !== null){
retour['tagId'] = tagId.toUpperCase()
client_globale.emit('envoieTagId',retour)
console.log('--> demande carte, envoi tag id = ' + tagId.toUpperCase())
retour = null
} else {
// console.log('-> Aucune demande, carte :' + card.uid.toString().toUpperCase())
console.log('-> Aucune demande, carte :' + tagId.toUpperCase())
if (client_globale !== null) {
client_globale.emit('infosTagId', tagId.toUpperCase())
}
}
})
vma405Emitter.on('msgVma405', (msg) => {
console.log('msgVma405 =', msg)
})
// --- commandes système ---
/** @function
* Obtenir ip extérieur (wan/box)
*/
function obtenirIpWan() {
const prog = spawn('curl', ['ifconfig.me'])
prog.stdout.on('data', (data) => {
prog.resultatRequete = data.toString()
})
prog.on('close', (code) => {
if (code === 0 ){
// ok: ip = prog.resultatRequete
} else {
// erreur
}
})
}
/**
* Obtenir des données de configuration d'un fichier (.chromium_env)
* @param {Array} rechercher - liste des varaibles à rechercher ddans le fichier
* @param {String} fichier - nom du fichier à lire
* @returns {{msg, erreur: number}|{valeurs: {}, erreur: number}}
*/
function obtenirConfigurationDunFichier(rechercher,fichier) {
try {
const fic = fs.readFileSync(fichier, {encoding:'utf8', flag:'r'}).split('\n')
let obj = {}
for (let index = 0; index < fic.length; index++) {
let ligne = fic[index].toString()
if (ligne.length > 0 && ligne[0] !== '#' && ligne.indexOf('=') !== -1) {
let tab = ligne.split('=')
for ( let im in rechercher) {
mot = rechercher[im]
if (mot === (tab[0].trim())) {
obj[tab[0].trim()] = tab[1].trim()
}
}
}
}
return {erreur: 0, valeurs: obj}
} catch (error) {
return {erreur:1 , msg: error}
}
}
function afficherInfoServeur(donnees){
// console.log('-> fonction afficherInfoServeur !')
// console.log('donnees = ', donnees)
if (donnees.erreur === 0) {
let bruteUrl = donnees.valeurs.url
let posDeuxSlashs = bruteUrl.indexOf('//') + 2
let posFinDomaine = bruteUrl.indexOf('/wv/login_hardware')
let domaine = bruteUrl.substring(posDeuxSlashs,posFinDomaine)
let onclique = ''
if (donnees.valeurs.front_type === "FPI") {
onclique = `onclick="clavierVirtuel.obtPosition('serveur');clavierVirtuel.afficher('serveur', 'alpahMin')"`
}
let fronts = ['FPI', 'FOR']
let options = ''
for (let i = 0; i < fronts.length; i++) {
let sel = ''
console.log(`${ i} -> ${ fronts[i] } -- ${ donnees.valeurs.front_type }`)
if (fronts[i] === donnees.valeurs.front_type) {
sel = 'selected'
}
options += ``
}
return `
Serveur: ${ domaine }
`
} else {
return `
Erreur
donnees.msg
`
}
}
/** @function
* Teste l'url avec curl
* @param {Sring} url - url à tester
* @param {Number} nbMaxStderr - nombre maxi d'évènement Stderr avant de sortir de la fonction
*/
function testUrl(url, nbMaxStderr) {
console.log(`-> fonction testUrl, url = ->${ url }<-`)
const prog = spawn('curl', ['-I', url])
prog.nbMaxStderr = nbMaxStderr
prog.nbStderr = 0
prog.resultatRequete = "404"
etatUrl = 0
prog.stdout.on('data', (data) => {
let premiereLigne = data.toString().split('\n')[0]
prog.resultatRequete = premiereLigne.split(' ')[1]
})
prog.stderr.on('data', (data) => {
prog.nbStderr ++
if(prog.nbStderr === prog.nbMaxStderr) {
prog.kill()
}
})
prog.on('close', (code) => {
// header 307 = redirection temporaire
// header 308 = redirection permanente
console.log('réponse test serveur = ', prog.resultatRequete)
if(prog.resultatRequete === '200' || prog.resultatRequete === '307' || prog.resultatRequete === '308') {
etatUrl = 1
}
client_globale.emit('etatUrlServeur', prog.resultatRequete)
})
}
function modifierConfigurationWifi(data) {
console.log('-> fonction modifierConfigurationWifi !')
console.log('data = ', data)
let template = `country=FR
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
ssid="${ data.essid }"
psk="${ data.passePhrase }"
scan_ssid=1
}
`
try {
fs.writeFileSync("/etc/wpa_supplicant/wpa_supplicant.conf", template, {flag: "w"})
client_globale.emit('modificationWifi', {
erreur: 0,
msg: `
Modification wifi effectuée,
réseau = ${ data.essid }
Redémmarer l'appareil !
`
})
} catch (erreur) {
client_globale.emit('modificationWifi', {
erreur: 1,
msg: `
Erreur configuration wifi
${ erreur }
`
})
}
}
function afficherInfosWifi() {
// console.log('-> fonction afficherInfosWifi !')
const prog = spawn('iwconfig', [])
prog.stdout.on('data', (data) => {
let lignes = data.toString().split('\n')
for (let i = 0; i < lignes.length; i++) {
let ligne = lignes[i]
if (ligne.indexOf('ESSID') !== -1) {
let tmpData = ligne.split(':')
let etatWifi = 'on'
let essid = ''
if (tmpData[1].includes('off')){
etatWifi = 'off'
} else {
essid = tmpData[1].trim().replace(/"/g, '')
}
let tmpData2 = ligne.split(' ')
prog.resultat = {interface: tmpData2[0], etat: etatWifi, essid: essid}
break
}
}
})
prog.on('close', (code) => {
if (code === 0) {
// wifi actif
// if (prog.resultat.etat === 'on' && donneesFichierConfiguration.erreur === 0) {
// uniquement sur pi
if (donneesFichierConfiguration.valeurs.front_type === "FPI") {
let onclique = ''
// if (donneesFichierConfiguration.valeurs.front_type === "FPI") {
oncliqueEssid = `onclick="clavierVirtuel.obtPosition('essid');clavierVirtuel.afficher('essid', 'alpahMin')"`
oncliquePasse = `onclick="clavierVirtuel.obtPosition('pp');clavierVirtuel.afficher('pp', 'alpahMin')"`
// }
let fragHtml = `
Ssid: ${ prog.resultat.essid }
`
client_globale.emit('retourInfosWifi', fragHtml)
}
// }
}
})
}
/**
* Lancer chromium
* @param {Number|1|2} - etape
*/
function lancerChromium(etape, dataFichier) {
console.log('-> fonction lancerChromium !')
let optionsChromium = [], msgErreur = ''
console.log('dataFichier = ', dataFichier)
if (dataFichier.erreur === 0) {
data = dataFichier.valeurs
} else {
msgErreur = dataFichier.msg
}
if (msgErreur === '') {
if (etape === 1) {
// dev
if (dev === 1) {
optionsChromium = ['--disable-features=Translate', '--disable-pinch', '--remote-debugging-port=9222', '--noerrdialogs', '--disable-infobars', '--check-for-update-interval=31536000', 'http://127.0.0.1:3000']
} else {
// prod
optionsChromium = ['--disable-features=Translate', '--disable-pinch', '--noerrdialogs', '--disable-infobars', '--check-for-update-interval=31536000', 'http://127.0.0.1:3000']
}
} else {
// dev
console.log('-> etape 2, url = ', data.url)
if (dev === 1) {
optionsChromium = ['--disable-features=Translate', '--disable-pinch', '--remote-debugging-port=9222', '--noerrdialogs', '--disable-infobars', '--check-for-update-interval=31536000', data.url]
} else {
// prod
optionsChromium = ['--disable-features=Translate', '--disable-pinch', '--noerrdialogs', '--disable-infobars', '--check-for-update-interval=31536000', data.url]
}
}
// mode kiosk uniquement pi
if (data.front_type === "FPI") {
optionsChromium.push('--kiosk')
}
if (msgErreur === '') {
const userAgent = `{"hostname":"${data.hostname}", "token": "${data.token}", "password":"${data.password}","modeNfc":"${data.mode_nfc}","front":"${data.front_type}","ip":"${obtenirIp('public', 'ipv4')}"}`
console.log('userAgent = ', userAgent)
optionsChromium.push(`--user-agent=${userAgent}`)
console.log('optionsChromium = ', optionsChromium)
// Lance chromium
const demChromium = spawn('chromium-browser', optionsChromium)
demChromium.stdout.on('data', (data) => {
console.log(`demChromium - stdout: ${data}`)
});
demChromium.stderr.on('data', (data) => {
console.error(`demChromium - stderr: ${data}`)
})
demChromium.on('close', (code) => {
console.log(`demChromium - child process exited with code ${code}`)
if (code === 0) {
console.log('--> Chromium démarrer !')
}
})
}
} else {
console.log('Erreur: ', msgErreur)
}
}
function lancerApplication(){
console.log('-> fonction lancerApplication !')
const dataConf = obtenirConfigurationDunFichier(['hostname', 'token', 'password', 'front_type', 'url', 'mode_nfc'], './.chromium_env')
if (dataConf.erreur === 0) {
let prog
if (dataConf.valeurs.front_type === "FPI") {
prog = spawn('pkill', ['chromium'])
} else {
prog = spawn('pkill', ['chrome'])
}
prog.stdout.on('data', (data) => {
console.log('stdout: ', data.toString())
})
prog.stderr.on('data', (data) => {
console.log('stderr: ', data.toString())
})
prog.on('close', (code) => {
if (code === 0) {
console.log('--> Chromium arrêter !')
const dataFichier = obtenirConfigurationDunFichier(['hostname', 'token', 'password', 'front_type', 'url', 'mode_nfc'], './.chromium_env')
lancerChromium(2, dataFichier)
}
})
} else {
console.log('Erreur: ', dataConf.msg)
}
}
function afficherFrontType() {
console.log('-> fonction afficherFrontType !')
console.log('donneesFichierConfiguration = ', donneesFichierConfiguration)
if (donneesFichierConfiguration.erreur === 0) {
return donneesFichierConfiguration.valeurs.front_type
} else {
return 'inconnu'
}
}
function rnd(min, max) {
return Math.round(Math.random() * ((max+1) - min) + min,0);
}
function generer_mot_de_passe(longueur) {
let mot = '';
let lettre = TAB[rnd(0,max_TAB)];
for(let i=0;i<(longueur);i++){
while (mot.indexOf(lettre)!=-1) {
lettre = TAB[rnd(0,59)];
}
mot += lettre;
}
return mot
}
function modifierConfigurationServeur(data) {
// console.log('-> fonction modifierConfigurationServeur !')
let proto = 'https'
// Développement serveur = "#serveur.com#", donne un protocol http et serveur = "serveur.com"
let serveur = data.serveurDomaine.toString()
// console.log('0 = ',serveur[0], ' -- dernier = ',serveur[(serveur.length-1)])
if (serveur[0] === '#' && serveur[(serveur.length-1)] === '#') {
proto = 'http'
serveur = data.serveurDomaine.toString().substring(1,(serveur.length-1))
}
donnees = obtenirConfigurationDunFichier(['hostname', 'token', 'password', 'front_type', 'url', 'mode_nfc'], './.chromium_env')
if (donnees.erreur === 0) {
let motDePasse = generer_mot_de_passe(16)
if (data.genererMotDePasse === false) {
motDePasse = donnees.valeurs.password
}
let template = `#utilisateur
hostname = ${data.user}
#front
front_type = ${data.typeFront}
#url du serveur
#url = http://django-local.org:8001/wv/login_hardware
url = ${proto}://${serveur}/wv/login_hardware
#mode_nfc = NFCMO
mode_nfc = ${ donnees.valeurs.mode_nfc }
password = ${ motDePasse }
token = ${ donnees.valeurs.token }
`
try {
fs.writeFileSync(".chromium_env", template)
client_globale.emit('modificationServeur', {erreur: 0, serveurDomaine: serveur})
testUrl(serveur, 14)
redemarrerChromium()
} catch (error) {
client_globale.emit('modificationServeur', {erreur: 1})
}
} else {
client_globale.emit('modificationServeur', {erreur: 1})
}
}
// --- serveur http ---
let typeMime = {
"aac":"audio/aac","abw":"application/x-abiword","arc":"application/octet-stream","avi":"video/x-msvideo","azw":"application/vnd.amazon.ebook",
"bin":"application/octet-stream","bz":"application/x-bzip","bz2":"application/x-bzip2","csh":"application/x-csh","css":"text/css","csv":"text/csv",
"doc":"application/msword","docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document","eot":"application/vnd.ms-fontobject",
"epub":"application/epub+zip","gif":"image/gif","htm":"text/html","html":"text/html","ico":"image/x-icon","ics":"text/calendar","jar":"application/java-archive",
"jpeg":"image/jpeg","jpeg":"image/jpeg","js":"application/javascript","json":"application/json","mid":"audio/midi","midi":"audio/midi","mpeg":"video/mpeg",
"mpkg":"application/vnd.apple.installer+xml","odp":"application/vnd.oasis.opendocument.presentation","ods":"application/vnd.oasis.opendocument.spreadsheet",
"odt":"application/vnd.oasis.opendocument.text","oga":"audio/ogg","ogv":"video/ogg","ogx":"application/ogg","otf":"font/otf","png":"image/png","pdf":"application/pdf",
"ppt":"application/vnd.ms-powerpoint","pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation","rar":"application/x-rar-compressed",
"rtf":"application/rtf","sh":"application/x-sh","svg":"image/svg+xml","swf":"application/x-shockwave-flash","tar":"application/x-tar","tif":"image/tiff",
"tiff":"image/tiff","ts":"application/typescript","ttf":"font/ttf","vsd":"application/vnd.visio","wav":"audio/x-wav","weba":"audio/webm","webm":"video/webm",
"webp":"image/webp","woff":"font/woff","woff2":"font/woff2","xhtml":"application/xhtml+xml","xls":"application/vnd.ms-excel",
"xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","xml":"application/xml","xul":"application/vnd.mozilla.xul+xml","zip":"application/zip",
"3gp":"video/3gpp audio/3gpp","3g2":"video/3gpp2 audio/3gpp2",
"7z":"application/x-7z-compressed"
}
let www = process.cwd() + '/www/'
console.log('www = ', www)
function retour404(res){
res.writeHead(404, {'Content-Type': 'text/html'});
res.write('Page inconnue !');
res.end();
}
function renderHtml(contenu, ctx) {
// let contenuTp1, contenuTp2, contenuTp3, contenuTp4
contenu = contenu.toString()
let rendu = contenu.toString().replace(/{{\s*[\w\.]+\s*}}/g, function(match, token) {
let clef = match.replace(/ /g,'').replace('{{','').replace('}}','')
console.log('-> match = ', match, ' -- clef = ', clef)
return ctx[clef]
})
contenu = {}
return rendu
}
// lire la conf. dans le fichier .chromium_env
donneesFichierConfiguration = obtenirConfigurationDunFichier(['hostname', 'token', 'password', 'front_type', 'url', 'mode_nfc'], './.chromium_env')
const serveur = http.createServer(function(req, res){
let url = req.url;
// routes
let ctx = {}
if(url=='/') {
url = 'index.html'
ctx = {
fontType: afficherFrontType(),
nomAppareil: os.hostname(),
afficherInfoServeur: afficherInfoServeur(donneesFichierConfiguration),
urlServeur: donneesFichierConfiguration.url,
ip: obtenirIp('public','ipv4'),
typeLecteurNfc: typeLecteurNfc,
typeserveurNfc: 'nodejs'
}
}
if(url=='/favicon.ico') url = 'img/favicon2.ico'
fichier = www + url.substring(0,url.length);
//assets
let posDerPoint = url.lastIndexOf('.')
let extention = ''
if(posDerPoint != -1){
extention = url.substring(posDerPoint+1,url.length);
if(extention.toLowerCase() == 'css') contentType = 'text/css';
contentType = typeMime[extention.toLowerCase()];
}
try {
let contenuFichier = fs.readFileSync(fichier)
// rendre du html
if (extention === 'html') {
contenuFichier = renderHtml(contenuFichier, ctx)
}
res.writeHead(200, {"Content-Type": contentType})
res.write(contenuFichier)
res.end();
console.log('-> url = '+url+' -- fichier :'+fichier+' -- contentType = '+contentType+' -> chargé !');
} catch (err) {
console.log('-> url = ' + url + ' -- Erreur: ' + err)
retour404(res);
}
})
// --- socket.io ---
const options = {
// allowEIO3: true,
cors: {
origin: "*",
methods: ["PUT", "GET", "POST"]
}
}
const IO = require('socket.io')(serveur,options)
// middleware
IO.use(function(socket, next){
let token = socket.handshake.query.token
// console.log('token reçu = '+token+' -- TOKEN = '+TOKEN)
if (token === TOKEN){
return next()
} else {
next(new Error("ERREUR d'autentification !"))
}
})
IO.on('connection', client => {
client_globale = client;
client_globale.on('demandeTagId', (data) => {
retour = data;
console.log('-> demandeTagIdg = '+JSON.stringify(retour))
})
client_globale.on('AnnuleDemandeTagId', () => {
retour = null
})
client_globale.on('disconnect', () => {
console.log('Client déconnecté !!')
})
client_globale.on('validerModifierWifi', (data) => {
modifierConfigurationWifi(data)
})
client_globale.on('validerModifierServeur', (data) => {
modifierConfigurationServeur(data)
})
client_globale.on('testerUrlServeur', (urlATester) => {
console.log('-> test url serveur = ',urlATester)
testUrl(urlATester, 12)
})
client_globale.on('donnerInfosWifi', () => {
afficherInfosWifi()
})
client_globale.on('lancerApplication', () => {
lancerApplication()
})
})
// lancement serveur http
serveur.listen(PORT, ADR, () => {
console.log(`le serveur écoute http://localhost:${PORT}`)
})
const dataConf = obtenirConfigurationDunFichier(['hostname', 'token', 'password', 'front_type', 'url', 'mode_nfc'], './.chromium_env')
lancerChromium(1,dataConf)