@ -16,6 +16,12 @@ const subclass = '192.168.4.'
const app = express ( ) ;
const app = express ( ) ;
app . use ( express . static ( path . resolve ( _ _dirname , "." , "examples" ) ) ) ;
app . use ( express . static ( path . resolve ( _ _dirname , "." , "examples" ) ) ) ;
app . use ( function ( req , res , next ) {
res . header ( "Access-Control-Allow-Origin" , "*" ) ;
res . header ( "Access-Control-Allow-Headers" , "Origin, X-Requested-With, Content-Type, Accept" ) ;
next ( ) ;
} ) ;
process . title = 'offtopus' // offline-octopus seems too long
process . title = 'offtopus' // offline-octopus seems too long
const filename = 'editor.html'
const filename = 'editor.html'
@ -33,20 +39,41 @@ if (fs.existsSync( configFilePath ) ){
const configurationFromFile = JSON . parse ( fs . readFileSync ( configFilePath ) . toString ( ) )
const configurationFromFile = JSON . parse ( fs . readFileSync ( configFilePath ) . toString ( ) )
localServices = configurationFromFile
localServices = configurationFromFile
}
}
console . log ( localServices )
// note that this is crucial to populate properly as this is what allow recombination
/ * e . g o n q u e s t
spascanodesecure https localhost 7778 / engine /
requires CORS to fetch here
fetch ( 'https://192.168.4.3:8082/available' )
. then ( r => r . json ( ) )
. then ( r => { if ( r ) addNewNote ( 'available' ) } )
gitea http localhost 3000 /
pmwiki http localhost 4000 / pmwiki . php
sshd see quest in ssh config , specific user and port
* /
const utilsCmd = { // security risk but for now not accepting user input so safer
const utilsCmd = { // security risk but for now not accepting user input so safer
//'update' : { desc: 'note that will lose the state, e.g foundpeers', cmd: 'killall '+process.title+' && ' },
//'update' : { desc: 'note that will lose the state, e.g foundpeers', cmd: 'killall '+process.title+' && ' },
// should first download the new version and proceed only if new
// should first download the new version and proceed only if new
// e.g git clone deck@localhost:~/Prototypes/offline-octopus/
// e.g git clone deck@localhost:~/Prototypes/offline-octopus/
// should see /sshconfig
// should see /sshconfig
// tried git instaweb but unable without lighttpd/apache
// would probably be problematic with https anyway
// ideally all handles within node
// ideally all handles within node
'shutdown' : { cmd : 'shutdown -h now' } , // not available everywhere, e.g unrooted Quest
'shutdown' : { cmd : 'shutdown -h now' } , // not available everywhere, e.g unrooted Quest
'listprototypes' : { cmd : 'ls' , context : { cwd : propath } ,
'listprototypes' : { cmd : 'ls' , context : { cwd : propath } ,
format : res => res . toString ( ) . split ( '\n' )
format : res => res . toString ( ) . split ( '\n' )
} ,
} ,
//'npmfind' : { desc: 'package manager finder', cmd: 'find . -wholename "*node_modules/acorn"' },
// security risk if relying on user provided name, e.g replacing acorn by user input
// example that could be generalized to other package managers e.g .deb or opkg
}
}
// example to disentangle own work for cloning existing repositories
// find ~/Prototypes/ -depth -maxdepth 4 -wholename "*/.git/config" | xargs grep -l git.benetou.fr | sed "s|.*Prototypes/\(.*\)/.git/config|\1|"
const instructions = `
const instructions = `
/ h o m e / d e c k / . s s h /
/ h o m e / d e c k / . s s h /
trusted context , i . e on closed WiFi and over https , still . could check as bearer
trusted context , i . e on closed WiFi and over https , still . could check as bearer
@ -76,6 +103,13 @@ app.get('/', (req, res) => {
res . send ( instructions )
res . send ( instructions )
} )
} )
app . get ( '/authtestviaheader' , ( req , res ) => {
if ( req . header ( 'authorization' ) != 'Bearer ' + md5fromPub ) { res . sendStatus ( 401 ) ; return ; }
res . sendStatus ( 200 )
// fetch('/authtestviaheader', {headers: {'authorization': 'Bearer '+ bearer}}).then(r=>r.text()).then(t=>console.log(t))
// prevents from showing in browser history but also makes testing slightly harder
} )
app . get ( '/authtest' , ( req , res ) => {
app . get ( '/authtest' , ( req , res ) => {
if ( req . query ? . bearer != md5fromPub ) { res . send ( auth _instructions ) ; return ; }
if ( req . query ? . bearer != md5fromPub ) { res . send ( auth _instructions ) ; return ; }
// relying on this line for each specific route
// relying on this line for each specific route
@ -83,6 +117,7 @@ app.get('/authtest', (req, res) => {
// this is done ONLY to avoid mistakes on a secure LAN
// this is done ONLY to avoid mistakes on a secure LAN
res . json ( { msg : "success" } )
res . json ( { msg : "success" } )
} )
} )
app . get ( '/pwa' , ( req , res ) => {
app . get ( '/pwa' , ( req , res ) => {
// for offline use on mobile or VR headset
// for offline use on mobile or VR headset
// should try to sync back when devices connect back
// should try to sync back when devices connect back
@ -95,7 +130,6 @@ app.get('/pwa', (req, res) => {
let resultFromLastGlobalCmd = { }
let resultFromLastGlobalCmd = { }
// should check on e.g publicKey or md5fromPub
app . get ( '/allpeers/exec' , ( req , res ) => {
app . get ( '/allpeers/exec' , ( req , res ) => {
if ( req . query ? . bearer != md5fromPub ) { res . send ( auth _instructions ) ; return ; }
if ( req . query ? . bearer != md5fromPub ) { res . send ( auth _instructions ) ; return ; }
if ( ! req . query . cmdName ) {
if ( ! req . query . cmdName ) {
@ -107,6 +141,7 @@ app.get('/allpeers/exec', (req, res) => {
+ '&bearer=' + req . query . bearer
+ '&bearer=' + req . query . bearer
let opt = { rejectUnauthorized : false }
let opt = { rejectUnauthorized : false }
https . get ( url , opt , res => {
https . get ( url , opt , res => {
// to simplify with fetch and promises
let data = '' ;
let data = '' ;
res . on ( 'data' , chunk => {
res . on ( 'data' , chunk => {
data += chunk ;
data += chunk ;
@ -120,7 +155,7 @@ app.get('/allpeers/exec', (req, res) => {
console . log ( err . message ) ;
console . log ( err . message ) ;
} ) . end ( )
} ) . end ( )
} )
} )
res . json ( { msg : 'started' } ) // could redirect('/all/result') too after a timeout
res . json ( { msg : 'started' } ) // could redirect('/all/result') instead after a timeout
}
}
} )
} )
app . get ( '/allpeers/result' , ( req , res ) => {
app . get ( '/allpeers/result' , ( req , res ) => {
@ -143,20 +178,28 @@ function execConfiguredCommand(cmdName){
return resultFromExecution
return resultFromExecution
}
}
// app.get('/interface/unregister', (req, res) => {
// app.get('/interface/register', (req, res) => {
// app.get('/interface/register', (req, res) => {
// consider uinput to access devices proper, e.g physical keyboard
// could be use for e.g reMarkable2, Quest2, etc with specifically accepted or prefered formats
// could be use for e.g reMarkable2, Quest2, etc with specifically accepted or prefered formats
// app.get('/interface/unregister', (req, res) => {
app . get ( '/services/unregister' , ( req , res ) => {
app . get ( '/services' , ( req , res ) => {
res . json ( { msg : 'not yet implemented' } )
// should be updated via register/unregister
res . json ( localServices )
} )
} )
app . get ( '/services/register' , ( req , res ) => {
app . get ( '/services/register' , ( req , res ) => {
// see localServices to load and save in configFilePath
res . json ( { msg : 'not yet implemented' } )
res . json ( { msg : 'not yet implemented' } )
// example {name:'hmdlink', desc:'share URL between local devices', protocol:'http', port:8082, path: '/hmdlink', url:'http://192.168.4.3:8082/hmdlink'},
// example {name:'hmdlink', desc:'share URL between local devices', protocol:'http', port:8082, path: '/hmdlink', url:'http://192.168.4.3:8082/hmdlink'},
} )
} )
app . get ( '/services/unregister' , ( req , res ) => {
res . json ( { msg : 'not yet implemented' } )
} )
app . get ( '/updates' , ( req , res ) => {
app . get ( '/updates' , ( req , res ) => {
// see utilsCmd['update']
// could rely on a git reachable by all peers
// could rely on a git reachable by all peers
// this might be feasible from this very https server as read-only
// this might be feasible from this very https server as read-only
// surely feasible via ssh
// surely feasible via ssh
@ -171,12 +214,6 @@ app.get('/recentfiles', (req, res) => {
res . json ( { msg : 'not yet implemented' } )
res . json ( { msg : 'not yet implemented' } )
} )
} )
app . get ( '/services' , ( req , res ) => {
// could be probbed first to check for availability
// should be updated also via register/unregister
res . json ( localServices )
} )
let dynURL = 'https://192.168.4.1/offline.html'
let dynURL = 'https://192.168.4.1/offline.html'
app . get ( '/hmdlink/set' , ( req , res ) => { // could be a PUT instead
app . get ( '/hmdlink/set' , ( req , res ) => { // could be a PUT instead
// e.g http://192.168.4.3:8082/hmdlink/set?url=http://192.168.4.3:8082/114df5f8-3921-42f0-81e7-48731b563571.thumbnails/f07120ba-0ca1-429d-869f-c704a52b7aa3.png
// e.g http://192.168.4.3:8082/hmdlink/set?url=http://192.168.4.3:8082/114df5f8-3921-42f0-81e7-48731b563571.thumbnails/f07120ba-0ca1-429d-869f-c704a52b7aa3.png
@ -320,4 +357,3 @@ const webServer = https.createServer(credentials, app);
webServer . listen ( port , ( ) => {
webServer . listen ( port , ( ) => {
console . log ( "listening on " + protocol + "://localhost:" + port ) ;
console . log ( "listening on " + protocol + "://localhost:" + port ) ;
} ) ;
} ) ;