Compare commits

...

24 Commits

Author SHA1 Message Date
cd1261418a Added code to redirect the user if they are permitted to access the GLink, and show an error JS alert if they are not 2023-06-19 01:14:18 -05:00
96abdd9852 Added code to check if the user is within the radius for the GLink 2023-06-19 01:13:31 -05:00
22c85234da Sent the requested glink to reqloc.html as a GET variable, so that the Glink can be sent to the PHP file 2023-06-17 13:56:02 -05:00
4bba4f9410 NOT FINISHED: Created a file to process the user's location 2023-06-17 13:55:05 -05:00
d928ad2ce3 Created file to request the user's location to determine if they are allowed to acces the glink 2023-06-17 13:54:31 -05:00
63050a8065 Changed variable names to match HTML document 2023-06-17 13:54:09 -05:00
0b08c1ce9c Added code to hide radius drop-down menu if geo-restriction checkbox was not selected 2023-06-17 13:53:51 -05:00
b7a8602e34 Added code to wait for location to be retrieved before allowing user to submit, and hid the radius drop-down if geo-location wasn't checked 2023-06-15 23:00:21 -05:00
42eff5e0fa Added code to redirect the user to a different page if the GLink they requested is geo-restricted 2023-06-15 18:49:31 -05:00
3d36c2704a Added code to retrieve the user's location and store it in the database 2023-06-15 18:48:36 -05:00
ae036686b8 Added code to fetch the user's location, and send it as a GET/POST variable 2023-06-12 15:29:24 -05:00
70f91c7586 Fixed bug where I accessed the database without opening a session 2023-06-12 15:28:30 -05:00
913d53b757 Added form field to allow user to georestrict the link 2023-06-12 15:28:02 -05:00
8b68547644 Added code to generate a random GLink if the user doesn't submit one 2023-06-09 20:03:30 -05:00
0f85fcf021 Made the Glink field optional 2023-06-09 20:03:01 -05:00
1d4606db27 Added code to redirect the user if the database query returns a URL 2023-06-08 21:36:33 -05:00
116bbe5218 Started working on redirect when user enters a GLink 2023-06-08 10:46:59 -05:00
1b52864952 Added server-side checks to input 2023-06-08 10:46:41 -05:00
92b70e632b Added code to print out the inserted data, and to check if the data was inserted by querying the database for the inserted data 2023-06-08 01:32:30 -05:00
c81937d6a5 Added code to insert data into Cassandra DB 2023-06-06 23:53:32 -05:00
f451850601 DO NOT USE - SWITCHED TO PHP INSTEAD - Added code to make database query 2023-06-06 13:23:27 -05:00
3bc6a56516 Added PHP file to make database queries 2023-06-06 13:22:15 -05:00
536af5f9c5 Removed event parameter from function so that it could be used with the HTML form 'onsubmit' 2023-06-06 13:21:57 -05:00
e5bdf2cc2c Switched to PHP instead of node.js, fixed bug where PHP would not be called regardless of input 2023-06-06 13:21:23 -05:00
7 changed files with 478 additions and 72 deletions

68
checkloc.php Normal file
View File

@@ -0,0 +1,68 @@
<?php
// FUNCTION TO CALCULATE HAVERSINE DISTANCE GIVEN COORDINATES OF
// TWO POINTS, AND RADIUS (IN KM)
function haversine_distance($lat1, $long1, $lat2, $long2, $radius) {
$term_1 = $lat2 - $lat1;
$term_1 = $term_1 / 2;
$term_1 = sin($term_1);
$term_1 = pow($term_1, 2);
$term_2 = $long2 - $long1;
$term_2 = $term_2 / 2;
$term_2 = sin($term_2);
$term_2 = pow($term_2, 2);
$term_2 = $term_2 * cos($lat1);
$term_2 = $term_2 * cos($lat2);
$distance = $term_1 + $term_2;
$distance = sqrt($distance);
$distance = asin($distance);
$distance = $distance * 2;
$distance = $distance * $radius;
return $distance;
}
function km_to_miles($distance) {
return $distance * 0.62137119;
}
$user_lat = $_GET["latitude"];
$user_lat = $user_lat * (M_PI / 180);
$user_long = $_GET["longitude"];
$user_long = $user_long * (M_PI / 180);
$glink = $_GET["glink"];
$cluster = Cassandra::cluster()->withPersistentSessions(true)->build();
$keyspace = 'glink';
$session = $cluster->connect($keyspace);
$statement = $session->prepare('SELECT latitude,longitude,radius,url FROM data WHERE shortlink=? ALLOW FILTERING;');
$result = $session->execute($statement,array('arguments' => array($glink)));
$link_lat = floatval($result[0]['latitude']);
$link_lat = $link_lat * (M_PI / 180);
$link_long = floatval($result[0]['longitude']);
$link_long = $link_long * (M_PI / 180);
$target_radius = intval($result[0]['radius']);
$url = $result[0]['url'];
$distance = haversine_distance($link_lat, $link_long, $user_lat, $user_long, 6371.009);
$distance = km_to_miles($distance);
if ($distance <= $target_radius) {
printf("%s",$url);
} else {
printf("B");
}
// Check the database to see if user is allowed to access the URL. If they are, respond 'Yes' (for the time being), if they are not, respond 'No' (for the time being).
// To check if the user is allowed to access the URL, check if the distance between their location and the location in the database is less than the radius. To compute the
// distance, use something like Haversine Forumla.
?>

View File

@@ -7,17 +7,34 @@
<body>
<div id="root">
<h1>Link Shortener</h1>
<form id="form" action="result.js">
<form id="form" method="GET" action="result.php" onsubmit="return validate()">
<!-- <form id="form"> -->
<label for="url">URL:</label><span class="mandatory">*</span>
<input type="text" name="url" id="URL" value="example.com" required><br><br>
<input type="text" name="url" id="URL" value="https://example.com" required><br><br>
<label for="labels">GLink:</label><span class="mandatory">*</span>
<label for="GLink" id="labels" class="glink">glink.zip/</label><input type="text" name="glink" id="GLink" class="glink" value="exampleWebsite" required>
<label for="GLink" id="labels" class="glink">glink.zip/</label><input type="text" name="glink" id="GLink" class="glink" value="exampleWebsite">
<span role="alert" id="error" aria-hidden="true">Invalid URL</span>
<br><br>
<label for="restricted">Geo-restricted?: </label> <input type="checkbox" name="restricted" id="restricted"> <span id="loadingText" style="position: relative; left: 20px;"></span>
<br><br>
<label for="radius" hidden="hidden" id="radius_label">Radius: </label> <span id="mandatory-radius" class="mandatory" hidden="hidden">*</span>
<select name="radius" id="radius" hidden="hidden">
<option value="" selected disabled hidden>Select a radius</option>
<option value="5">5 mi</option>
<option value="10">10 mi</option>
<option value="15">15 mi</option>
<option value="20">20 mi</option>
</select>
<br><br>
<input type="submit" id="button" value="Zip It!">
<input type="hidden" name="latitude" id="latitude">
<input type="hidden" name="longitude" id="longitude">
</form>
<hr>
<div>

230
index.js
View File

@@ -1,67 +1,175 @@
const submit = document.getElementById("button");
submit.addEventListener('click', validate);
function validate(e) {
e.preventDefault();
const url = document.getElementById("URL");
const glink = document.getElementById("GLink");
// if (!url) {
// /* Flag */
// }
let valid = true;
const domainExp = new RegExp("http(s)*:\\/\\/[a-zA-Z0-9\\-]+(\\.[a-zA-Z0-9\\-]+)+");
const filepathExp = new RegExp("[a-zA-Z]+");
let count = 0;
let index = -1;
let domain = "";
let filepath = "";
for (let i=0; i < url.value.length; i++) {
if (url.value.charAt(i) == '/') {
count++;
}
if (count == 3) {
index = i;
break;
}
// const submit = document.getElementById("button");
mycheckbox = document.getElementById("restricted");
mycheckbox.addEventListener('change',checkboxCallback);
window.onload = function() {
if (mycheckbox.checked) {
document.getElementById("radius_label").hidden = false;
document.getElementById("mandatory-radius").hidden = false;
var radiusSelect = document.getElementById("radius");
radiusSelect.hidden = false;
radiusSelect.required = true;
}
if (count >= 3) {
domain = url.value.substring(0, index);
if (index == url.value.length - 1) {
filepath = url.value.charAt(index);
}
var lat = document.getElementById("latitude");
lat.setValue = function(newValue) {
this.value = newValue;
valueReceived();
}
function valueReceived() {
let load = document.getElementById("loadingText");
load.innerHTML = "Location retrieved";
load.style.color = "green";
}
function valueRequested() {
let load = document.getElementById("loadingText");
load.innerHTML = "Location requested. Please wait...";
load.style.color = "red";
}
function checkboxCallback(event) {
const radiusLabel = document.getElementById("radius_label");
const radiusSelect = document.getElementById("radius");
const mandatoryRadius = document.getElementById("mandatory-radius");
if (event.currentTarget.checked) {
radiusLabel.hidden = false;
mandatoryRadius.hidden = false;
radiusSelect.hidden = false;
radiusSelect.required = true;
valueRequested();
getLocation();
} else {
radiusLabel.hidden = true;
mandatoryRadius.hidden = true;
radiusSelect.hidden = true;
radiusSelect.required = false;
}
}
function getLocation() {
console.log("GeoLocation");
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
console.log("Your browser does not support geolocation.");
}
}
function showPosition(position) {
console.log("Gotten positions");
console.log(position.coords.latitude);
console.log(position.coords.longitude);
document.getElementById("latitude").setValue(position.coords.latitude);
document.getElementById("longitude").value = position.coords.longitude;
console.log("done");
}
// submit.addEventListener('click', validate);
function validate() {
//e.preventDefault();
const checked = document.getElementById("restricted");
if (checked.checked) {
const lat = document.getElementById("latitude");
const long = document.getElementById("longitude");
if (lat.value === "" || long.value === "") {
/* wait */
return false
}
}
const url = document.getElementById("URL");
let glink = document.getElementById("GLink");
const error = document.getElementById("error");
// if (!url) {
// /* Flag */
// }
let valid = true;
const domainExp = new RegExp("^http(s)*:\\/\\/[a-zA-Z0-9\\-]+(\\.[a-zA-Z0-9\\-]+)+$");
const filepathExp = new RegExp("^[a-zA-Z]+$");
const glinkExp = new RegExp("^[a-zA-Z]*$");
let glinkStr = glink.value;
let count = 0;
let index = -1;
let domain = "";
let filepath = "";
for (let i = 0; i < url.value.length; i++) {
if (url.value.charAt(i) == '/') {
count++;
}
if (count == 3) {
index = i;
break;
}
}
if (count >= 3) {
domain = url.value.substring(0, index);
if (index == url.value.length - 1) {
filepath = url.value.charAt(index);
} else {
filepath = url.value.substring(index, url.value.length - 1);
}
alert("Domain is " + domain + " filepath is " + filepath);
} else {
filepath = url.value.substring(index, url.value.length - 1);
domain = url.value;
}
alert("Domain is " + domain + " filepath is " + filepath);
} else {
domain = url.value;
}
console.log(domain);
if (domain.match(domainExp)) /** and is available? */{
const error = document.getElementById("error");
if (error.classList.contains("visible")) {
error.classList.remove("visible");
}
if (url.classList.contains("invalid")) {
url.classList.remove("invalid");
}
url.classList.add("valid");
error.setAttribute('aria-hidden', true);
error.setAttribute('aria-invalid', false);
console.log("Valid");
return valid;
} else {
console.log(domain);
/*flag*/
const error = document.getElementById("error");
error.classList.add("visible");
//error.classList.add("hidden");
if (url.classList.contains("valid")) {
url.classList.remove("valid");
if (glinkStr === "") {
var result = window.confirm("You have left the glink field blank. A random one will be generated for you.");
if (result === false) {
return false;
}
}
url.classList.add("invalid");
error.setAttribute('aria-hidden', false);
error.setAttribute('aria-invalid', true);
}
}
if (domain.match(domainExp) && glinkStr.match(glinkExp))/** and is available? */{
if (error.classList.contains("visible")) {
error.classList.remove("visible");
}
if (url.classList.contains("invalid")) {
url.classList.remove("invalid");
}
url.classList.add("valid");
if (glink.classList.contains("invalid")) {
glink.classList.remove("invalid");
}
glink.classList.add("valid");
error.setAttribute('aria-hidden', true);
error.setAttribute('aria-invalid', false);
console.log("Valid with url= " +url.value+ " glink=" +glink);
return valid;
} else {
/*flag*/
error.classList.add("visible");
//error.classList.add("hidden");
if (!domain.match(domainExp)) {
if (url.classList.contains("valid")) {
url.classList.remove("valid");
}
url.classList.add("invalid");
} else {
if (url.classList.contains("invalid")) {
url.classList.remove("invalid");
}
url.classList.add("valid");
}
if (!glinkStr.match(glinkExp)) {
if (glink.classList.contains("valid")) {
glink.classList.remove("valid");
}
glink.classList.add("invalid");
} else {
if (glink.classList.contains("invalid")) {
glink.classList.remove("invalid");
}
glink.classList.add("valid");
}
error.setAttribute('aria-hidden', false);
error.setAttribute('aria-invalid', true);
return false;
}
}

42
redirect.php Normal file
View File

@@ -0,0 +1,42 @@
<?php
use Cassandra;
$uri = $_SERVER['REQUEST_URI'];
$uri = substr($uri,1);
$matches_uri = preg_match('/^[a-zA-Z]+$/',$uri);
if (($matches_uri == 0) || ($matches_uri == false)) {
header("Location: http://glink.zip/");
exit;
} else {
$cluster = Cassandra::cluster()->withPersistentSessions(true)->build();
$keyspace = 'glink';
$session = $cluster->connect($keyspace);
$statement = $session->prepare('SELECT url,is_geo FROM data WHERE shortlink=? ALLOW FILTERING;');
$result = $session->execute($statement,array('arguments' => array($uri)));
if ($result->count() == 0) {
printf('The given GLink was invalid, and doesn\'t point to a specific web page.');
exit;
}
foreach($result as $row) {
if (is_null($row)) {
printf('The given GLink was invalid, and doesn\'t point to a specific web page.');
exit;
} else {
if ($row['is_geo'] == true) {
header("Location: https://glink.zip/reqloc.html?glink=" . $uri);
exit;
} else {
header("Location: " . $row['url']);
exit;
}
}
}
}
?>

59
reqloc.html Normal file
View File

@@ -0,0 +1,59 @@
<html>
<head>
<title>Location needed</title>
</head>
<body onload="get_location()">
This link is geo-restricted. Your location is needed to verify that you are authorized to access this link.
<script>
var params = new URLSearchParams(window.location.search);
var glink = params.get("glink");
var lat;
var long;
var method = "GET";
var request;
function requestHandler() {
if (request.readyState === XMLHttpRequest.DONE) {
if (request.status === 200) {
if (request.responseText == "B") {
alert("You are not authorized to access this GLink, as you are outside the permitted radius. If you think this is an error, please try again on a mobile device.");
} else {
window.location.replace(request.responseText);
}
} else {
console.log("Error sending data to server.");
}
}
}
function storeLocation(position) {
lat = position.coords.latitude;
long = position.coords.longitude;
}
function callbackFunction(position) {
storeLocation(position);
request = new XMLHttpRequest();
request.onreadystatechange = requestHandler;
if (method == "GET") {
request.open("GET","/checkloc.php?latitude=" + encodeURIComponent(lat) + "&longitude=" + encodeURIComponent(long) + "&glink=" + encodeURIComponent(glink));
request.send();
} else if (method == "POST") {
request.open("POST","/checkloc.php");
request.send("latitude=" + encodeURIComponent(lat) + "&longitude=" + encodeURIComponent(long));
}
}
function get_location() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(callbackFunction);
} else {
alert('You cannot access this GLink as your browser does not support geolocation.');
}
}
</script>
</body>
</html>

View File

@@ -1,8 +0,0 @@
const cassandra = require('cassandra-driver');
const client = new cassandra.Client({
contactPoints: ['127.0.0.1:9042'],
keyspace: 'glink',
});
const query =

120
result.php Normal file
View File

@@ -0,0 +1,120 @@
<?php
function gen_base62_rand_shortlink($len) {
$rand_bytes = random_bytes(intval(($len * 2) / 3));
$rand_string = base64_encode($rand_bytes);
$rand_string = str_replace("+","",$rand_string);
$rand_string = str_replace("/","",$rand_string);
$rand_string = str_replace("=","",$rand_string);
if (mb_strlen($rand_string) < $len) {
$curlen = mb_strlen($rand_string);
$rand_string = $rand_string . gen_rand_shortlink($len - $curlen);
}
return $rand_string;
}
function gen_rand_shortlink($len) {
$to_return = '';
$possible_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
while (mb_strlen($to_return) < $len) {
$to_return = $to_return . $possible_chars[rand(0, mb_strlen($possible_chars)-1)];
}
return $to_return;
}
ini_set('display_errors', 1);
$cluster = Cassandra::cluster()->withPersistentSessions(true)->build();
$keyspace = 'glink';
$session = $cluster->connect($keyspace);
$url = $_GET["url"];
if (isset($_GET["restricted"])) {
$is_geo = 1;
} else {
$is_geo = 0;
}
if ($is_geo == 1) {
$radius = $_GET["radius"];
$latitude = $_GET["latitude"];
$latitude = doubleval($latitude);
$longitude = $_GET["longitude"];
$longitude = doubleval($longitude);
}
$matches = preg_match('/^http(s)*:\\/\\/[a-zA-Z0-9\\-]+(\\.[a-zA-Z0-9\\-]+)+$/',$url);
if (($matches == 0) || ($matches == false)) {
printf("The URL entered was invalid. Please try again.");
return;
}
$shortlink = $_GET["glink"];
if ($shortlink != '') {
$matches_shortlink = preg_match('/^[a-zA-Z]+$/',$shortlink);
if (($matches_shortlink == 0) || ($matches_shortlink == false)) {
printf("The GLink entered was invalid. The GLink can only contain letters. Please try again.");
return;
}
} else {
/* generate a random shortlink */
gen_shortlink:
$rand_string = gen_rand_shortlink(6); /* the function is defined at the start of this file */
$shortlink = $rand_string;
/* Check if shortlink is already taken by querying the database */
$statement = $session->prepare('SELECT url FROM data WHERE shortlink=? ALLOW FILTERING');
$result = $session->execute($statement,array('arguments' => array($shortlink)));
if ($result->count() != 0) {
goto gen_shortlink;
}
}
//$statement = new Cassandra\SimpleStatement('SELECT name FROM data WHERE id=5');
$statement = $session->prepare('SELECT url FROM data WHERE shortlink=? ALLOW FILTERING');
$options = array('arguments' => array($shortlink));
$result = $session->execute($statement,$options);
if ($result->count() != 0) {
printf('That GLink is already taken. Please try another one.');
exit;
}
$rand_num = rand(0,99999999);
$statement = $session->prepare('INSERT INTO data (id, url, shortlink, is_geo, radius, latitude, longitude, when_created) VALUES (?,?,?,?,?,?,?,toTimestamp(now())) USING TTL 20');
if ($is_geo == 1) {
$options = array($rand_num,$url,$shortlink,boolval($is_geo),intval($radius), $latitude, $longitude);
} else {
$options = array($rand_num,$url,$shortlink,boolval($is_geo),null,null,null);
}
$result = $session->execute($statement,array('arguments' => $options));
//$stringRepresentation= json_encode($result[0]);
//printf("%s\n\n\n",$stringRepresentation);
//foreach($result as $row) {
// if (is_null($row)) {
// printf('Unsuccessful');
// } else {
printf('Successful: The URL you entered was: %s and your GLink is: https://glink.zip/%s', $url,$shortlink);
// }
//}
//printf('Done');
?>