Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use of local and session storage. Concept of sign-in/sign-out. Ready Form URL. #7

Merged
merged 5 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions 404.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>EasyForm</title>
<meta name="description" content="Free, self-hosted, open-source form backend solution. No installation required for hosting. Lightweight server runs in browser. Backend sends form data as a Telegram bot to your Telegram account.">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
<link rel="manifest" href="site.webmanifest">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>
<h1>Hello there! Feel free to post your message/comment/query to me</h1>
<form method="POST" target="hidden_iframe">
<input type="hidden" name="From" value="EasyFormURL">
<div class="row mt-2">
<div class="col">
<input type="email" class="form-control" name="Email" placeholder="Your Email" autocomplete="on" required>
</div>
<div class="col">
<input type="text" class="form-control" name="Name" placeholder="Your Name" autocomplete="on" required>
</div>
<input type="text" class="form-control mt-2" name="Message" placeholder="Your Message" required>
</div>
<button type="submit" id="submit" class="btn btn-info mt-2" onclick="alert('Thanks for your message!');">Post</button>
<button type="reset" class="btn btn-warning mt-2">Reset</button>
</form>
<iframe name="hidden_iframe" src="about:blank" hidden></iframe>

<script>
document.getElementById("submit").setAttribute("formaction", atob(location.pathname.substr(10,).replace(/_/g,'+').replace(/-/g,'/')));
</script>
</body>
</html>
12 changes: 6 additions & 6 deletions app/bg-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function urlEncoded2Json(str){
for (let el of arr) {
let elArray = el.split('=');
let val = decodeURIComponent(elArray[1].replace( /\+/g, ' ' )).replace(/"/g,'\\"'); // Decoded and escaped
eval('obj.' + elArray[0] +'="' + val +'"');
eval(`obj.${elArray[0]}="${val}"`);
}

return JSON.stringify(obj);
Expand All @@ -29,15 +29,15 @@ async function pollApi(getFrom, postTo, TGchatID) {

if (! response.ok) {
errLvl = 1; // Set error to critical/fatal
throw "GET @ " + getFrom + " status: " + response.status;
throw `GET @ ${getFrom} status: ${response.status}`;
}

data = urlEncoded2Json(await response.text());
// Send URL decoded form data as JSON string to main for logging. Also pass an error level.
postMessage([data, 0]);

} catch (error) {
console.error(Date() + ': Error making GET request --', error);
console.error(`${Date()}: Error making GET request -- ${error}`);
// Send error to main for logging. Error level: 1 for high priority / fatal.
postMessage(['Failed to fetch form data.', errLvl]);
return;
Expand All @@ -57,17 +57,17 @@ async function pollApi(getFrom, postTo, TGchatID) {
})

if (! response.ok) {
throw "POST @ " + postTo + " status: " + response.status +". Is chat ID = " + TGchatID + " ok?";
throw `POST @ ${postTo} status: ${response.status}. Is chat ID = ${TGchatID} ok?`;
}

} catch (error) {
console.error(Date() + ': Error making POST request --', error);
console.error(`${Date()}: Error making POST request -- ${error}`);
// Send error to main for logging. Error level: 2 for low priority / non-fatal.
postMessage(['Failed to post form data to Telegram.', errLvl]);
return;
}

console.log(Date() + ": Relay complete.");
console.log(`${Date()}: Relay complete.`);
};

relay(); // Start the first relay
Expand Down
81 changes: 60 additions & 21 deletions app/server.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
// Main entry point for the server. Deploys background worker in "bg-worker.js" for handling networking.

spaHide("jsAlert");

let myWorker = null;
let getFrom, postTo, TGchatID;
let numReadMsgs = 0;
let numTotalMsgs = 0;
const logs = document.getElementById("logs");
const toggleServer = document.getElementById("toggleServer");

function logThis(report) {
const row = document.createElement("p");
row.append(Date() + ": " + report);
row.append(`${Date()}: ${report}`);
logs.prepend(row);
}

Expand Down Expand Up @@ -37,7 +38,7 @@ function inbox(json){
const cell = document.createElement("td");

// Create a text entry:
entry = eval("data." + keysEnumArray[key]);
entry = eval(`data.${keysEnumArray[key]}`);

// Append entry to cell:
cell.append(entry);
Expand Down Expand Up @@ -70,37 +71,45 @@ function genUUID() {
}

const fetchChatID = async () => {
logThis("Fetching Telegram chat ID")
const apiEndpoint = 'https://api.telegram.org/bot' + document.getElementById("apiKey").value + '/getUpdates';
logThis("Fetching Telegram chat ID");
const apiEndpoint = 'https://api.telegram.org/bot' + document.getElementById("TGbotKey").value + '/getUpdates';
const response = await fetch(apiEndpoint); // Make request
if (! response.ok) {
logThis("Telegram API status code:" + response.status +". Is Bot API Token ok?");
logThis(`Telegram API status code: ${response.status}. Is Bot API Token ok?`);
alert("Failed to fetch chat ID. Check your Bot API Token!");
return;
}
const data = await response.json();
document.getElementById("chatID").value = data.result[0].message.chat.id;
try {
const TGchatID = data.result[0].message.chat.id;
document.getElementById("chatID").value = TGchatID;
localStorage.setItem("TGchatID", TGchatID);
} catch (e) {
alert("Failed to fetch chat ID. Send any text to the Telegram Bot then try again.");
}
}

function config() {
const relayList = ["https://ppng.io", "https://piping.glitch.me", "https://demo.httprelay.io/link"];
const uuid = document.getElementById("uuid").value;
// Choose a random index in [0, relayList.length]. Use first two nibbles of uuid as random number in range [0,256].
const randomIdx = Math.floor(parseInt(uuid.substr(0,2),16)*relayList.length/256);
getFrom = relayList[randomIdx] + '/' + uuid;
postTo = 'https://api.telegram.org/bot' + document.getElementById("apiKey").value + '/sendMessage';
TGchatID = document.getElementById("chatID").value;
document.getElementById("config").innerHTML = '<p class="alert alert-success">HTML Form Action URL: <u>' + getFrom + '</u></p>';
document.getElementById("testFormBtn").setAttribute("formaction", getFrom);
spaShowHide("testForm");
document.getElementById("config").scrollIntoView();
const getFrom = relayList[randomIdx] + '/' + uuid;
localStorage.setItem("getFrom", getFrom);
const postTo = 'https://api.telegram.org/bot' + document.getElementById("TGbotKey").value + '/sendMessage';
localStorage.setItem("postTo", postTo);
spaGoTo("server");
localStorage.setItem("loggedIn", "true");
}

function startWorker() {
if (getFrom === undefined) {
config();
if (myWorker || sessionStorage.getItem("server")) {
alert('Another server is already running. Only one server can run at a time.');
return;
} else {
sessionStorage.setItem("server", "live");
}

myWorker = new Worker("app/bg-worker.js");

// Register handler for messages from the background worker
Expand All @@ -109,29 +118,40 @@ function startWorker() {
const msg = e.data[0];
if (! errLvl) {
inbox(msg);
logThis('RECEIVED: ' + msg);
logThis(`RECEIVED: ${msg}`);
} else if (errLvl === 1) {
stopWorker();
logThis('FATAL ERROR: ' + msg + ' See console for details.');
logThis(`FATAL ERROR: ${msg}. See console for details.`);
alert('Server stopped due to some critical error');
} else {
logThis('ERROR: ' + msg + ' See console for details.');
logThis(`ERROR: ${msg}. See console for details.`);
}
}

const getFrom = localStorage.getItem("getFrom");

// Communicate key data to the background worker
myWorker.postMessage([getFrom, postTo, TGchatID]);
myWorker.postMessage([getFrom, localStorage.getItem("postTo"), localStorage.getItem("TGchatID")]);

toggleServer.value = "Kill Server";
toggleServer.disabled = false;

logThis("Server started");
document.getElementById("serverStatus").innerHTML = 'Live <span class="spinner-grow spinner-grow-sm"></span>';

document.getElementById("formActionURL").innerHTML = `<p class="alert alert-success">HTML Form Action URL: <u>${getFrom}</u></p>`;
document.getElementById("readyForm").href = `./${btoa(getFrom).replace(/\+/g,'_').replace(/\//g,'-')}`;
document.getElementById("testFormBtn").setAttribute("formaction", getFrom);
spaShow("testForm");
}

function stopWorker() {
if (! myWorker) {
return;
}
myWorker.terminate();
myWorker = null;
sessionStorage.removeItem("server");
console.log("Worker terminated");
toggleServer.value = "Launch Server"
logThis("Server stopped");
Expand All @@ -145,3 +165,22 @@ function toggleWorker() {
startWorker();
}
}

function signout() {
stopWorker();
localStorage.clear();
location.reload();
}

function main() {
// Enable config if no prior settings found in localStorage
if (localStorage.getItem("loggedIn")) {
startWorker();
spaGoTo("server");
} else {
spaGoTo("setup");
}

}

spaHide("jsAlert");
40 changes: 24 additions & 16 deletions app/spa.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,30 @@
const spaHomePageID = document.querySelector(".spa-page").id; // Assuming first spa-page class is the home / hero page
let spaCurrentPageID = spaHomePageID;

{
const pages = document.getElementsByClassName("spa-page");
function spaShow(id) {
document.getElementById(id).style.display = 'block';
}

for (let el of pages) {
el.style.display = 'none';
function spaHide(id) {
document.getElementById(id).style.display = 'none';
}

function spaToggle(id) {
let x = document.getElementById(id);
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}

function spaGoTo(id) {
document.getElementById(spaCurrentPageID).style.display = 'none';
spaShow(id);
spaCurrentPageID = id;
spaTop();
}

function spaTop(){
document.getElementById(spaCurrentPageID).scrollIntoView();
}
Expand All @@ -21,19 +37,11 @@ function spaBottom(){
document.getElementById(spaCurrentPageID).scrollIntoView(false);
}

function spaGoTo(id) {
document.getElementById(spaCurrentPageID).style.display = 'none';
document.getElementById(id).style.display = 'block';
spaCurrentPageID = id;
spaTop();
}
{
const pages = document.getElementsByClassName("spa-page");

function spaShowHide(id) {
let x = document.getElementById(id);
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
for (let el of pages) {
el.style.display = 'none';
}
}

Expand Down
Loading