summaryrefslogtreecommitdiff
path: root/client.js
diff options
context:
space:
mode:
Diffstat (limited to 'client.js')
-rwxr-xr-xclient.js274
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.)");