const path = require('path'); const express = require('express'); const app = express(); const staticPath = path.join(__dirname, "/public"); const fs = require('fs'); const bcrypt = require('bcrypt'); const saltRounds = 10; var bodyParser = require('body-parser') const cassandra = require('cassandra-driver'); const {compare} = require("bcrypt"); const client = new cassandra.Client({ contactPoints: ['127.0.0.1:9042'], localDataCenter: 'datacenter1', keyspace: 'glink' }); let id = 1; /* Ideally should initialize id to be nextFromDB or write to file and read */ const port = 63342; // Port that the server listens on */ const RADIUS_OF_EARTH_IN_MILES = 3958.7614580848; app.use( bodyParser.json() ); app.use(bodyParser.urlencoded({ extended: true })); app.use(express.static(staticPath)); const GLINK_SIZE = 6; function getRandomGLink() { let glink = ""; glink = newString(GLINK_SIZE); validateLink(glink); return glink; } function validateLink(glink) { let qry = "SELECT id FROM data WHERE glink = ? allow filtering"; client.execute(qry, [glink], {}, (err, result) => { if(err) { console.log(err.message); glink = null; } if (result.rows.length === 0) { console.log("Done"); } else { console.log(glink); glink = getRandomGLink(); } }); return glink; } function newString(n) { let str = ""; let symbols = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; for (let i = 0; i < n; i ++) { str += symbols.charAt(Math.floor(Math.random() * 52)); } return str; } function nextId() { let next = id; id = id + 1; return next; } function filter(path) { if (path.match(new RegExp("^/[a-zA-Z]+/*$"))) { if (path.charAt(0) === '/') { path = path.substring(1); } return path; } else { console.log("failed check. path is " + path); return null; } } function checkFileExistsSync(fp){ let exists = true; try{ fs.accessSync(fp, fs.constants.F_OK); }catch(e){ exists = false; } return exists; } function calculateDistance(lat1, lat2, long1, long2) { console.log(lat1 + " " + lat2 + " " + long1 + " " + long2); lat1 = lat1 * (Math.PI / 180); lat2 = lat2 * (Math.PI / 180); long1 = long1 * (Math.PI / 180); long2 = long2 * (Math.PI / 180); /* 2 asin(((lat2 - lat1)/2) ^ 2)*/ return (2 * Math.asin(Math.sqrt(Math.pow(Math.sin((lat2 - lat1)/2), 2) + Math.pow(Math.sin((long2 - long1)/2), 2) * Math.cos(lat1) * Math.cos(lat2))) * RADIUS_OF_EARTH_IN_MILES); } // app.get('/', (request, response) => { // response.render("index.html"); // }) app.get('/node_modules/', (request, response) => { response.redirect("./error.html"); }) app.get('/public/', (request, response) => { response.redirect("./error.html"); }) const query = "INSERT INTO data (id, url, glink, time, isGeo, radius, latitude, longitude) VALUES (?, ?, ?, toTimestamp(now()), ?, ?, ?, ?)"; app.post('/__add', function(req, res) { let input_url = req.body.url; let input_glink = req.body.glink; let input_checkbox = req.body.restricted; let input_radius = req.body.radiusSelect; let input_latitude = req.body.latitude; let input_longitude = req.body.longitude; let geoBool = false; let geoString = "off"; //console.log("Received query " + input_url + " and " + input_glink); if (input_checkbox) { geoString = "on"; geoBool = true; } else { input_radius = null; input_latitude = null; input_longitude = null; } if (input_glink === "") { input_glink = getRandomGLink(); let currID = nextId(); console.log(currID, input_url, input_glink, geoBool, input_radius, input_latitude, input_longitude) client.execute(query, [currID, input_url, input_glink, geoBool, input_radius, input_latitude, input_longitude], {prepare: true}, function(err,result) { if (err) { res.send("

" + err.message + "

"); } else { res.send("" + "

" + "New entry has been added with geolocation turned " + geoString + " and url = " + req.body.url + " and glink = " + "

" + "" + "
" + "" + "
" + "" + ""); } }); } else { let selectQuery = "SELECT id FROM data where glink = ? allow filtering"; console.log(input_glink); client.execute(selectQuery, [input_glink],{} ,function(err, result) { if (result.rows.length === 0) { let currID = nextId(); console.log("values are: " + currID, input_url, input_glink, geoBool, input_radius, input_latitude, input_longitude); client.execute(query, [currID, input_url, input_glink, geoBool, input_radius, input_latitude, input_longitude], {prepare: true}, function(err,result) { if (err) { res.send("

" + err.message + "

"); } else { res.send("" + "

" + "New entry has been added with geolocation turned " + geoString + " and url = " + req.body.url + " and glink = " + "

" + "" + "
" + "" + "
" + "" + ""); } }); } else { res.send("

This glink has already been registered. Please try a different glink

"); } }); } }) app.post('/__check', function(req, res) { let user_latitude = req.body.latitude; let user_longitude = req.body.longitude; let req_path = req.body.glink; let selQry = "select url, latitude, longitude, radius from data where glink = ? allow filtering"; client.execute(selQry, [req_path], {}, function(err, result) { if (result.rows.length === 0) { res.redirect("/error.html"); } else { let page = result.rows[0]["url"]; let latitude = result.rows[0]["latitude"]; let longitude = result.rows[0]["longitude"]; let radius = result.rows[0]["radius"]; console.log(user_latitude + user_longitude); let distance = calculateDistance(user_latitude, latitude, user_longitude, longitude); console.log(distance + " " + radius); if (distance < radius) { console.log("inside radius"); res.writeHead(301, {Location: page}); res.end(); } else { res.redirect("./error.html "); console.log("Outside radius"); } } }) }) app.post('/__login', function(req, res) { let email = req.body.email; let password = req.body.password; /** TODO: Validate to make sure user-password exists */ let emailRX = new RegExp("^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(\\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z]+)+$"); let domainRX = new RegExp("[A-Za-z0-9!@#$%^&*]"); let minRXCharUp = new RegExp("[A-Z]"); let minRXCharLow = new RegExp("[a-z]"); let minRXNum = new RegExp("[0-9]"); let symRX = new RegExp("[!@#$%^&*]"); let selQry = "select password from account where email = ? allow filtering"; if (emailRX.test(email) && domainRX.test(password) && minRXNum.test(password) && minRXCharUp.test(password) && minRXCharLow.test(password) && symRX.test(password) && password.length >= 10) { client.execute(selQry, [email], {}, function(error, result) { if (error) { console.log(error.message); } else { if (result.rows[0].length === 0) { res.redirect("/error.html"); } else { let hash = result.rows[0]["password"]; bcrypt.compare(password, hash) .then(match => { if (match) { } else { res.redirect("/login.html"); } }) .catch(err => { console.log(err.message); }) } } }) } }); /* Redirect requests to corresponding entry in database */ app.get('/*', (request, response, cb) => { console.log("Entered"); let original_request = request.path; console.log(original_request); if (original_request.charAt(original_request.length - 1) === '/' && original_request.length > 1) { original_request = original_request.substring(0, original_request.length - 1); } let req_path = filter(original_request); if (!req_path) { if (checkFileExistsSync(original_request)) { response.redirect(original_request); } else { response.redirect("/error.html"); return cb(""); } } else { let geoQry = "select isGeo from data where glink = ? allow filtering"; client.execute(geoQry, [req_path], {}, function (err, result) { if (result.rows.length === 0) { response.redirect("/error.html"); } else { let isGeo = result.rows[0]["isgeo"]; if (isGeo) { response.send("

Redirecting you to the website! Please wait ...

"); response.end(); } else { let selQry = "select url from data where glink = ? allow filtering"; client.execute(selQry, [req_path], {}, function (err, result) { if (result.rows.length === 0) { response.redirect("/error.html"); } else { let page = result.rows[0]["url"]; console.log(page); response.writeHead(301, {Location: page}); response.end(); } }) } } }) } }) app.listen(port, function(){ console.log("server listening on port 63342"); }) /** Validate url and glink on client side as well */ /** Validate to make sure request is a file before sending it */