Caution
DISCLAIMER: This repository is purely Experimental in nature and should not be used commercially!
Fireburst OS is a Desktop environment in the browser with a VFS that aims to support as many filetypes as possible via WASM, Cheerpx, Cheerp and Cheerpj. This can include some desktop applications, namely linux ELF files. Fireburst also aims to provide other similar services such as BrowserCode, Github PAT Integration, and secure browsers such as Scramjet and Ultraviolet. Perhaps most importantly of all, Fireburst is designed to run on github pages making it very easy to deploy.
- Cheerpx
- Cheerp
- Cheerpj
- Eruda
- BrowserCode
- Scramjet
- Ultraviolet
- Eaglercraft
- jsnes
- Github Repository Editor
Fireburst runs on GitHub pages making it very easy to deploy; all you need is a browser and a github account. If you would rather use the demo it is located here
(steps 2-4 might be optional idk)
Fork Repository
Go to settings on your forked repository
Click on the secret values tab
Add a secret value titled BACKEND_URL see [Deploy Google Apps Script Backend](#Deploy Google Apps Scripts Backend)
Go to .github/workflows/deploy.yml on your fork and press run workflow or workflow_dispatch
It should redirect you to the workflows overview, when it finishes there should be a hyperlink that you can click on that will take you to your site! The URL should be https:// <your username> .github.io/ <your repo name> /
Enjoy!
The Google Apps Scripts backend is deployed separately as a Web App, the URL of said Web App is the value of the BACKEND_URL on GitHub Secrets.
Step-By-Step Deployment
- Go to Google Apps Scripts
- Create new Project
- Delete everything in the editor and paste the code below:
const ADMINS = ["admin.email.1@example.com", "admin.email.2@example.com"];
// 1. THE JSONP BYPASS HANDLER
function doGet(e) {
var res = handleRequest(e.parameter);
if (e.parameter.callback) {
// Return as a Javascript Execution to bypass CORS
return ContentService.createTextOutput(e.parameter.callback + '(' + JSON.stringify(res) + ')')
.setMimeType(ContentService.MimeType.JAVASCRIPT);
}
return ContentService.createTextOutput(JSON.stringify(res)).setMimeType(ContentService.MimeType.JSON);
}
function doPost(e) {
var req;
try { req = JSON.parse(e.postData.contents); } catch(err) { req = e.parameter; }
return ContentService.createTextOutput(JSON.stringify(handleRequest(req))).setMimeType(ContentService.MimeType.JSON);
}
// 2. THE UNIFIED LOGIC
function handleRequest(req) {
try {
var action = req.action;
var email = (req.email || "").toLowerCase().trim();
var password = req.password || "";
var room = req.room || "general";
const prop = PropertiesService.getScriptProperties();
if (action === "register") {
if (!email.includes("@")) return { error: "Invalid email." };
if (password.length < 4) return { error: "Password must be 4+ chars." };
if (prop.getProperty("user_" + email)) return { error: "Email already registered." };
prop.setProperty("user_" + email, password);
return { success: true };
}
if (action === "login") {
var storedPass = prop.getProperty("user_" + email);
if (!storedPass || storedPass !== password) return { error: "AuthFailed" };
return { success: true, isAdmin: ADMINS.includes(email) };
}
var authPass = prop.getProperty("user_" + email);
if (!authPass || authPass !== password) return { error: "AuthFailed" };
if (action === "getData") return { messages: getMessages(room), rooms: getRooms(), admin: ADMINS.includes(email) };
if (action === "send") { sendMessage(room, email, req.text); return { success: true }; }
if (action === "createRoom") { createRoom(req.roomName); return { success: true }; }
if (action === "deleteMessage") { if (ADMINS.includes(email)) deleteMessage(room, req.msgId); return { success: true }; }
return { error: "Unknown action" };
} catch(err) { return { error: err.toString() }; }
}
// 3. DATABASE FUNCTIONS
function getRooms() { return JSON.parse(PropertiesService.getScriptProperties().getProperty("rooms") || '["general"]'); }
function createRoom(name) { var r = getRooms(); if(!r.includes(name)) r.push(name); PropertiesService.getScriptProperties().setProperty("rooms", JSON.stringify(r)); }
function getMessages(room) {
var prop = PropertiesService.getScriptProperties();
var index = Number(prop.getProperty("room_" + room + "_index") || 1);
var msgs = [];
for(let i=1; i<=index; i++) { var raw = prop.getProperty("room_"+room+"_"+i); if(raw) msgs = msgs.concat(JSON.parse(raw)); }
return msgs.slice(-100);
}
function sendMessage(room, email, text) {
var prop = PropertiesService.getScriptProperties();
var index = Number(prop.getProperty("room_" + room + "_index") || 1);
var key = "room_" + room + "_" + index;
var msgs = JSON.parse(prop.getProperty(key) || "[]");
if(msgs.length >= 100) { index++; prop.setProperty("room_" + room + "_index", index); key = "room_" + room + "_" + index; msgs=[]; }
msgs.push({ id: Utilities.getUuid(), user: email, text: text, time: Date.now() });
prop.setProperty(key, JSON.stringify(msgs));
}
function deleteMessage(room, id) {
var prop = PropertiesService.getScriptProperties();
var index = Number(prop.getProperty("room_" + room + "_index") || 1);
for(let i=1; i<=index; i++) {
var key = "room_" + room + "_" + i;
var msgs = JSON.parse(prop.getProperty(key) || "[]");
var newMsgs = msgs.filter(m => m.id !== id);
if(newMsgs.length !== msgs.length) { prop.setProperty(key, JSON.stringify(newMsgs)); return; }
}
}- Replace the
ADMINSvalues with your email - Click
Deployand then configure as:- Execute As ME
- Anyone
- Then click
Deployand copy the URL that is outputed, that is yourBACKEND_URL
There are so many services and repositories that have assisted in the creation of this Repository so go over to CREDITS.md and check it out!
