diff options
Diffstat (limited to 'server/serverstore.js')
-rwxr-xr-x | server/serverstore.js | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/server/serverstore.js b/server/serverstore.js new file mode 100755 index 0000000..1d04530 --- /dev/null +++ b/server/serverstore.js @@ -0,0 +1,161 @@ +#!/usr/bin/env node + +var fs=require("fs"), + path=require("path"), + app=require("express")(), + bodyParser=require("body-parser"), + crypto=require("crypto"), + Persist=require("node-persist"), + glob=require("glob"); + +var HOSTNAME="tomsmeding.com",HTTPPORT=42420; + +Persist.initSync({}); + +var challenge=null; + +function renewChallenge(){ + var entropy=crypto.randomBytes(512); + var hasher=crypto.createHash("sha256"); + hasher.update(entropy); + challenge=hasher.digest("hex"); +} +setInterval(renewChallenge,8000); +renewChallenge(); + +var gencode=(function(){ + const startn=42424242; + const alphabet="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + var lastn=Persist.getItemSync("gencode_lastn"); + if(lastn==null)lastn=startn; + return function gencode(){ + var code="",coden=lastn; + while(coden){ + code+=alphabet[coden%alphabet.length]; + coden=~~(coden/alphabet.length); + } + if(lastn==0x7fffffff)lastn=0; //maximum value of a 32-bit int + else lastn++; + Persist.setItemSync("gencode_lastn",lastn); + if(lastn==startn)throw new Error("RUN OUT OF INDICES PANIC PANIC"); + while(code.length<6)code+="a"; + return code; + }; +})(); + + +app.use(bodyParser.raw({ + limit:"3mb", + type:"image/*" +})); + +app.use(bodyParser.text({ + type:"text/plain" +})); + + +app.get("/ss/challenge",function(req,res){ + res.end(challenge); +}); + + +app.param("userid",function(req,res,next,userid){ + var password=Persist.getItemSync("user_"+userid); + if(!password){ + res.sendStatus(404); + res.end("Non-existent userid"); + return; + } + req.ssuser=[userid,password]; + next(); +}); +app.param("authhash",function(req,res,next,authhash){ + var s=challenge+req.ssuser[1]; + var hasher=crypto.createHash("sha256"); + hasher.update(s); + var hashres=hasher.digest("hex"); + if(hashres!=authhash){ + res.sendStatus(403); + res.end("Invalid answer to challenge"); + return; + } + next(); +}); +app.param("fname",function(req,res,next,fname){ + req.sscode=gencode(); + req.ssfname=req.sscode+"_"+fname.replace(/[\x00-\x1F\/]/g,"").replace(/^\.+/,""); + next(); +}); +app.post("/ss/image/:userid/:authhash/:fname",function(req,res){ + try { + if(!fs.statSync("images").isDirectory())throw new Error; + } catch(e){ + fs.mkdirSync("images"); + if(!fs.statSync("images").isDirectory())throw new Error; + } + if(!fs.existsSync("images/"+req.ssuser[0])){ + fs.mkdirSync("images/"+req.ssuser[0]); + } + fs.writeFileSync("images/"+req.ssuser[0]+"/"+req.ssfname,req.body); + res.end("https://"+HOSTNAME+"/ss/get/"+req.ssuser[0]+"/"+req.sscode); +}); + + +app.param("reguserid",function(req,res,next,reguserid){ + req.ssreguserid=reguserid; + next(); +}); +app.post("/ss/registerx/:reguserid",function(req,res){ //pass password in body + var password=req.body; + if(Persist.getItemSync("user_"+req.ssreguserid)){ + res.sendStatus(409); //Conflict + res.end("That userid already exists"); + return; + } + Persist.setItemSync("user_"+req.ssreguserid,password); + res.sendStatus(200); + res.end(); +}); + + +app.get("/ss/exists/:reguserid",function(req,res){ + res.sendStatus(Persist.getItemSync("user_"+req.ssreguserid)?200:404); + res.end(); +}); + +app.get("/ss/checklogin/:userid/:authhash",function(req,res){ + res.sendStatus(200); //login checking is done in the authhash param + res.end(); +}); + + +app.param("ssimgcode",function(req,res,next,ssimgcode){ + req.ssimgcode=ssimgcode.replace(/[^a-zA-Z0-9]/g,""); + if(req.ssimgcode.length!=6){ + res.sendStatus(404); + res.end("Invalid or unknown image code"); + return; + } + next(); +}); +app.get("/ss/get/:userid/:ssimgcode",function(req,res){ + var files=glob.sync(__dirname+"/images/"+req.ssuser[0]+"/"+req.ssimgcode+"*"); + if(files.length==0){ + res.sendStatus(404); + res.end("Unknown image code"); + return; + } + if(files.length>1){ + console.log("More than one file matched; internal error"); + console.log(files); + res.sendStatus(500); + res.end("More than one file matched; internal error"); + return; + } + res.sendFile(files[0]); +}); + + +app.listen(42420,function(){ + console.log("Server started."); +}); |