summaryrefslogtreecommitdiff
path: root/server/serverstore.js
blob: e10ae9ad5762654848034e4170a2bc61b8f9b0de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#!/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 = Persist.create({
	dir:__dirname+"/persist",
	continuous:false,
	interval:false
});
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();

function gencode(){
	var alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
	var code = "";
	for(var i = 0; i < 6; i++) {
		code += alphabet[~~(Math.random() * alphabet.length)];
	}
	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.ssfname = 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]);
	}

	// Try until we get a unique code (enforced by "wx"), or we've failed 10 times
	for (var i = 0; i < 10; i++) {
		var code = gencode();
		var path = "images/" + req.ssuser[0] + "/" + code + "_" + req.ssfname;
		try {
			fs.writeFileSync(path, req.body, {flag: "wx"});
			res.end("https://" + HOSTNAME + "/ss/get/" + req.ssuser[0] + "/" + code);
			return;
		} catch(e) {
			if (i == 10) console.log(e);
			continue;
		}
	}

	res.sendStatus(500);
	res.end();
});


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.");
});