// 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 }
Tester Serveur
Modifier Serveur
Valider
` } 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 }
Modifier Wifi
Valider
` 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)