diff options
Diffstat (limited to 'client.js')
-rwxr-xr-x | client.js | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/client.js b/client.js new file mode 100755 index 0000000..00d4abb --- /dev/null +++ b/client.js @@ -0,0 +1,274 @@ +#!/usr/bin/env node + +var fs=require("fs"), + path=require("path"), + http=require("http"), + crypto=require("crypto"), + dialog=require("dialog"), + kbd=require("kbd"); + +var HOSTNAME="localhost",HTTPPORT=42420; + +var userid="0",password="-"; + + +var HOMEDIR=process.env.HOME||process.env.HOMEPATH||process.env.HOMEDIR||process.cwd(); +var WATCHDIR=HOMEDIR+"/Desktop"; +var ignored=[]; + +var currentState=[]; + +//lots of code taken/modified from tomsmeding/gvajnez +function collectDirState(dir){ + if(!dir)dir=directory; + //console.log("collectDirState("+dir+")"); + var list=fs.readdirSync(dir); + var result=[]; + var statinfo,i,j; + for(i=0;i<list.length;i++){ + for(j=0;j<ignored.length;j++){ + if(etc.endsWith(path.normalize(dir+"/"+list[i]),"/"+ignored[j]))break; + } + if(j<ignored.length)continue; + statinfo=fs.statSync(dir+"/"+list[i]); + /*if(statinfo.isDirectory()){ + result=result.concat(collectDirState(dir+"/"+list[i])); + } else if(statinfo.isFile()){*/ + result.push({ + name:path.resolve(dir+"/"+list[i]), + mode:statinfo.mode, + mtime:statinfo.mtime.getTime() + }); + //} + } + return result; +} + +function collectChanges(dir,state){ + if(!dir)dir=directory; + var i,j,obj; + var changes=[]; + for(i=0;i<state.length;i++){ + for(j=0;j<currentState.length;j++){ + if(state[i].name==currentState[j].name)break; + } + if(j==currentState.length|| + currentState[j].mode!=state[i].mode|| + currentState[j].mtime!=state[i].mtime){ + //either file didn't exist yet, or metadata has changed + changes.push(state[i]); + } + } + for(i=0;i<currentState.length;i++){ + for(j=0;j<state.length;j++){ + if(currentState[i].name==state[j].name)break; + } + if(j==state.length){ + //file doesn't exist anymore + changes.push(currentState[i]); + } + } + return changes; +} + +function handleChanges(changes){ + var i,match,namedate,now; + for(i=0;i<changes.length;i++){ + if(!fs.existsSync(changes[i].name))continue; //probably delete event + match=changes[i].name.match(/\/Screen Shot (\d{4}-\d{2}-\d{2}) at (\d{2}\.\d{2}\.\d{2}).png$/); + if(!match)continue; + namedate=new Date(match[1]+" "+match[2].replace(/\./g,":")); + if(!namedate)continue; + changes[i].mtime=new Date(changes[i].mtime); + now=new Date(); + if((now-changes[i].mtime)/1000>15||(now-namedate)/1000>15)continue; //15 seconds limit + sendfile(changes[i].name); + } +} + +function authhash(challenge,password){ + var s=challenge+password; + var hasher=crypto.createHash("sha256"); + hasher.update(s); + return hasher.digest("hex"); +} + +function getchallenge(cb){ + console.log("Going to request challenge..."); + var req=http.request({ + hostname:HOSTNAME, + port:HTTPPORT, + path:"/challenge", + method:"GET", + keepAlive:true //speed up the next request + },function(res){ + var body=""; + res.on("data",function(data){ + body+=data; + }); + res.on("end",function(){ + if(res.statusCode!=200){ + dialog.warn("Could not request challenge! Is your internet connection alive?\n\n"+body); + return; + } + console.log("challenge = "+body); + cb(body); + }); + }); + req.on("error",function(err){ + console.log(err); + }); + req.end(); +} +function sendfile(fname,retries){ + retries=retries!=null?retries:3; + var barefname; + var idx=fname.lastIndexOf("/"); + if(idx==-1)barefname=fname; + else barefname=fname.slice(idx+1); + getchallenge(function(challenge){ + var req=http.request({ + hostname:HOSTNAME, + port:HTTPPORT, + path:"/image/"+userid+"/"+authhash(challenge,password)+"/"+escape(barefname), + method:"POST", + headers:{ + "Content-Type":"image/png" + } + },function(res){ + var body=""; + res.on("data",function(data){ + body+=data; + }); + res.on("end",function(){ + if(res.statusCode!=200){ + if(retries>0)sendfileChallenge(fname,challenge,retries-1); + else { + dialog.warn("Could not upload image! Are your credentials still okay?\n\n"+body); + return; + } + } + console.log("Successful upload"); + fs.unlink(fname); //not sync, take your time + dialog.info(body); + }); + }); + req.on("error",function(err){ + console.log(err); + }); + req.end(fs.readFileSync(fname)); + }); +} + + +function userExists(userid,cb){ + var req=http.request({ + hostname:HOSTNAME, + port:HTTPPORT, + path:"/exists/"+userid, + method:"GET" + },function(res){ + if(res.statusCode==200)cb(true); + else if(res.statusCode==404)cb(false); + else { + console.log("Server returned status code "+res.statusCode+" for exists query!"); + } + }); + req.on("error",function(err){ + console.log(err); + }); + req.end(); +} + +function checkLogin(userid,password,cb){ + getchallenge(function(challenge){ + var req=http.request({ + hostname:HOSTNAME, + port:HTTPPORT, + path:"/checklogin/"+userid+"/"+authhash(challenge,password), + method:"GET" + },function(res){ + if(res.statusCode==200)cb(true); + else if(res.statusCode==404||res.statusCode==403)cb(false); + else { + console.log("Server returned status code "+res.statusCode+" for checklogin query!"); + } + }); + req.on("error",function(err){ + console.log(err); + }); + req.end(); + }); +} + +function registerUser(userid,password){ + var req=http.request({ + hostname:HOSTNAME, + port:HTTPPORT, + path:"/registerx/"+userid, + method:"POST", + headers:{ + "Content-Type":"text/plain" + } + },function(res){ + var body=""; + res.on("data",function(data){ + body+=data; + }); + res.on("end",function(){ + if(res.statusCode==200)console.log("Successfully registered user "+userid); + else if(res.statusCode==409)console.log("Conflict: "+body); + else console.log("Error: "+body); + }); + }); + req.on("error",function(err){ + console.log(err); + }); + req.end(password); +} + + + +process.stdout.write("Username? "); +userid=kbd.getLineSync().replace(/[^a-zA-Z0-9_-]/g,""); +process.stdout.write("Password? "); +kbd.setEcho(false); +password=kbd.getLineSync(); +kbd.setEcho(true); +console.log("\nChecking existence..."); + +userExists(userid,function(exists){ + if(exists){ + checkLogin(userid,password,function(ok){ + if(ok)console.log("User login ok."); + else { + console.log("Username or password incorrect!"); + process.exit(); + } + }); + return; + } + process.stdout.write("That username doesn't seem to exist. Register it? [y/N] "); + var response=kbd.getLineSync()[0]; + if(response=="y"||response=="Y")registerUser(userid,password); + else { + console.log("Not registered. Exiting."); + process.exit(); + } +}); + +var timeout=null; +var watcher=fs.watch(WATCHDIR,{persistent:true,recursive:false},function(ev,fname){ + //console.log("change in directory "+WATCHDIR+" (fname "+fname+")"); + if(timeout)return; + timeout=setTimeout(function(){ + var newstate=collectDirState(WATCHDIR); + var changes=collectChanges(WATCHDIR,newstate).map(function(o){o.name=o.name.replace(/^\.\//,"");return o;}); + currentState=newstate; + if(changes.length!=0)handleChanges(changes); + timeout=null; + //console.log(currentState); + },500); +}); +currentState=collectDirState(WATCHDIR); +console.log("-- (Client ready.)"); |