#!/usr/bin/env node var fs=require("fs"), path=require("path"), http=require("http"), crypto=require("crypto"), dialog=require("dialog"), kbd=require("kbd"), toClipboard=require("to-clipboard"); var HOSTNAME=process.argv[2]||"tomsmeding.nl",HTTPPORT=42420; console.log("Using server "+HOSTNAME); var lockfiledesc; var lockfilename="/tmp/.lock_serverstore_client_"+HOSTNAME; try {lockfiledesc=fs.openSync(lockfilename,"wx");} catch(e){ var lockedpid=+fs.readFileSync(lockfilename); var canoverwrite=false; if(isNaN(lockedpid))canoverwrite=true; try {process.kill(lockedpid,0);} catch(e){canoverwrite=true;} if(!canoverwrite){ console.log("Another copy of the serverstore client with the same hostname seems to be running."); console.log("If this is not the case, or intentional, delete the file "+lockfilename+" and try again."); process.exit(1); } lockfiledesc=fs.openSync(lockfilename,"w"); } fs.write(lockfiledesc,process.pid+"\n"); process.on("exit",function(){ fs.closeSync(lockfiledesc); fs.unlinkSync(lockfilename); }); 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;i60||(now-namedate)/1000>60)continue; //1 minute limit setTimeout(function(n){ return function(){sendfile(n);}; }(changes[i].name),100); } } 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)sendfile(fname,retries-1); else { dialog.warn("Could not upload image! Are your credentials still okay?\n\n"+body); return; } } console.log("Successful upload"); setTimeout(function(){ fs.unlink(fname,function(err){ //not sync, take your time if(err)console.log(err); }); },200); toClipboard.sync(body.trim()); dialog.info(body+"\n(Copied to clipboard.)"); }); }); req.on("error",function(err){ console.log(err); }); try{req.end(fs.readFileSync(fname));} catch(e){console.log(e);} }); } 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,retries){ retries=retries!=null?retries:3; 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){ if(retries>0)checkLogin(userid,password,cb,retries-1); else 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? "); (function(){ var hasher=crypto.createHash("sha256"); kbd.setEcho(false); var passinput=kbd.getLineSync(); hasher.update(passinput); kbd.setEcho(true); password=hasher.digest("hex"); })(); 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.)");