diff --git a/package-lock.json b/package-lock.json
index 33209c7..8e85d5e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "fullsend",
- "version": "1.8.1",
+ "version": "1.8.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "fullsend",
- "version": "1.8.1",
+ "version": "1.8.2",
"license": "MIT",
"dependencies": {
"bcryptjs": "^2.4.3",
diff --git a/package.json b/package.json
index 41a19b8..e2d13f3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "fullsend",
- "version": "1.8.1",
+ "version": "1.8.2",
"description": "Fullsend allows allowed users to send bulk text messages to groups of recipients",
"main": "server.js",
"scripts": {
diff --git a/public/changepassword.html b/public/changepassword.html
index 31b4a55..931b805 100644
--- a/public/changepassword.html
+++ b/public/changepassword.html
@@ -9,7 +9,7 @@
-
+
Fullsend | SMS notification from the web
@@ -41,6 +41,9 @@
+ -
+ DEV MODE
+
-
diff --git a/public/css/style.min.css b/public/css/style.min.css
new file mode 100644
index 0000000..ecc7592
--- /dev/null
+++ b/public/css/style.min.css
@@ -0,0 +1 @@
+#fullsendForm p small{line-height:1.2;display:block}#fullsendForm p small .reminder{color:var(--bs-dark-gray)}#navDev{cursor:default}.imessage{display:flex;flex-direction:column;font-family:-apple-system,"Helvetica Neue","Helvetica",sans-serif;font-size:1.25rem;margin:0 auto 1rem;max-width:600px;padding:.5rem 1.5rem}.imessage p{border-radius:1.15rem;line-height:1.25;max-width:75%;padding:.5rem .875rem;position:relative;word-wrap:break-word}.imessage p::before,.imessage p::after{bottom:-0.1rem;content:"";height:1rem;position:absolute}p.from-me{align-self:flex-end;background-color:#248bf5;color:#fff}p.from-me::before{border-bottom-left-radius:.8rem .7rem;border-right:1rem solid #248bf5;right:-0.35rem;transform:translate(0, -0.1rem)}p.from-me::after{background-color:#fff;border-bottom-left-radius:.5rem;right:-40px;transform:translate(-30px, -2px);width:10px}p[class^=from-]{margin:.5rem 0;width:-moz-fit-content;width:fit-content}p.from-me~p.from-me{margin:.25rem 0 0}p.from-me~p.from-me:not(:last-child){margin:.25rem 0 0}p.from-me~p.from-me:last-child{margin-bottom:.5rem}p.from-them{align-items:flex-start;background-color:#e5e5ea;color:#000}p.from-them:before{border-bottom-right-radius:.8rem .7rem;border-left:1rem solid #e5e5ea;left:-0.35rem;transform:translate(0, -0.1rem)}p.from-them::after{background-color:#fff;border-bottom-right-radius:.5rem;left:20px;transform:translate(-30px, -2px);width:10px}p[class^=from-].emoji{background:none;font-size:2.5rem}p[class^=from-].emoji::before{content:none}.no-tail::before{display:none}.margin-b_none{margin-bottom:0 !important}.margin-b_one{margin-bottom:1rem !important}.margin-t_one{margin-top:1rem !important}body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-weight:normal;margin:0}.container{margin:0 auto;max-width:600px;padding:1rem}h1{font-weight:normal;margin-bottom:.5rem}h2{border-bottom:1px solid #e5e5ea;color:#666;font-weight:normal;margin-top:0;padding-bottom:1.5rem}.comment{color:#222;font-size:1.25rem;line-height:1.5;margin-bottom:1.25rem;max-width:100%;padding:0}@media screen and (max-width: 800px){body{margin:0 .5rem}.container{padding:.5rem}.imessage{font-size:1.05rem;margin:0 auto 1rem;max-width:600px;padding:.25rem .875rem}.imessage p{margin:.5rem 0}}/*# sourceMappingURL=style.min.css.map */
\ No newline at end of file
diff --git a/public/css/style.min.css.map b/public/css/style.min.css.map
new file mode 100644
index 0000000..4882c5d
--- /dev/null
+++ b/public/css/style.min.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["style.scss"],"names":[],"mappings":"AAAA,sBACE,eAAA,CACA,aAAA,CAEA,gCACE,yBAAA,CAIJ,QACE,cAAA,CAGF,UACE,YAAA,CACA,qBAAA,CACA,iEAAA,CACA,iBAAA,CACA,kBAAA,CACA,eAAA,CACA,oBAAA,CAGF,YACE,qBAAA,CACA,gBAAA,CACA,aAAA,CACA,qBAAA,CACA,iBAAA,CACA,oBAAA,CAGF,uCAEE,cAAA,CACA,UAAA,CACA,WAAA,CACA,iBAAA,CAGF,UACE,mBAAA,CACA,wBAAA,CACA,UAAA,CAGF,kBACE,qCAAA,CACA,+BAAA,CACA,cAAA,CACA,+BAAA,CAGF,iBACE,qBAAA,CACA,+BAAA,CACA,WAAA,CACA,gCAAA,CACA,UAAA,CAGF,gBACE,cAAA,CACA,sBAAA,CAAA,iBAAA,CAGF,oBACE,iBAAA,CAGF,qCACE,iBAAA,CAGF,+BACE,mBAAA,CAGF,YACE,sBAAA,CACA,wBAAA,CACA,UAAA,CAGF,mBACE,sCAAA,CACA,8BAAA,CACA,aAAA,CACA,+BAAA,CAGF,mBACE,qBAAA,CACA,gCAAA,CACA,SAAA,CACA,gCAAA,CACA,UAAA,CAGF,sBACE,eAAA,CACA,gBAAA,CAGF,8BACE,YAAA,CAGF,iBACE,YAAA,CAGF,eACE,0BAAA,CAGF,cACE,6BAAA,CAGF,cACE,0BAAA,CAgBF,KACE,uHAAA,CASA,kBAAA,CACA,QAAA,CAGF,WACE,aAAA,CACA,eAAA,CACA,YAAA,CAGF,GACE,kBAAA,CACA,mBAAA,CAGF,GACE,+BAAA,CACA,UAAA,CACA,kBAAA,CACA,YAAA,CACA,qBAAA,CAGF,SACE,UAAA,CACA,iBAAA,CACA,eAAA,CACA,qBAAA,CACA,cAAA,CACA,SAAA,CAGF,qCACE,KACE,cAAA,CAGF,WACE,aAAA,CAGF,UACE,iBAAA,CACA,kBAAA,CACA,eAAA,CACA,sBAAA,CAGF,YACE,cAAA,CAAA","file":"style.min.css"}
\ No newline at end of file
diff --git a/public/css/style.scss b/public/css/style.scss
index 83069dc..dce0fbb 100644
--- a/public/css/style.scss
+++ b/public/css/style.scss
@@ -7,7 +7,9 @@
}
}
-
+#navDev {
+ cursor: default;
+}
.imessage {
display: flex;
diff --git a/public/fullsend.html b/public/fullsend.html
index 736a9d2..5d5dffb 100644
--- a/public/fullsend.html
+++ b/public/fullsend.html
@@ -10,7 +10,7 @@
-
+
Fullsend | SMS notification from the web
@@ -60,6 +60,9 @@ Selected recipients
+ -
+ DEV MODE
+
-
diff --git a/public/group-management.html b/public/group-management.html
index 1b9dbaa..425c685 100644
--- a/public/group-management.html
+++ b/public/group-management.html
@@ -8,7 +8,7 @@
-
+
Fullsend | SMS notification from the web
@@ -40,6 +40,9 @@
+ -
+ DEV MODE
+
-
diff --git a/public/help.html b/public/help.html
index c960db7..69d8148 100644
--- a/public/help.html
+++ b/public/help.html
@@ -9,7 +9,7 @@
-
+
Fullsend | SMS notification from the web
@@ -40,6 +40,9 @@
+ -
+ DEV MODE
+
-
@@ -63,6 +66,10 @@ Fullsend
Changelog
+
v1.8.2
+
+ Adds a flag for development that shows "DEV MODE" in the navbar.
+
v1.8.1
Fixes how sessions are handled on the user's side.
diff --git a/public/index.html b/public/index.html
index f915a7b..d6023f6 100644
--- a/public/index.html
+++ b/public/index.html
@@ -9,7 +9,7 @@
-
+
Fullsend | SMS notification from the web
@@ -40,6 +40,9 @@
+ -
+ DEV MODE
+
-
diff --git a/public/js/fullsend.js b/public/js/fullsend.js
index 1d4eb74..becee5b 100644
--- a/public/js/fullsend.js
+++ b/public/js/fullsend.js
@@ -108,6 +108,11 @@ const handleSwitch = async (e) => {
};
const sendMessage = async () => {
+ // Respect server-side sending flag exposed via APP_CONFIG
+ if (window.APP_CONFIG && window.APP_CONFIG.sendingEnabled === false) {
+ alert('Sending is disabled in this environment.');
+ return -1;
+ }
let error = false;
document.getElementById("noMessageError").style.display = "none";
document.getElementById("noRecipientsError").style.display = "none";
@@ -156,11 +161,15 @@ const sendMessage = async () => {
const handleMessagePreview = () => {
const fsmText = document.getElementById("fullsendMessage").value.trim();
- if (fsmText != "") {
- document.getElementById("sendButton").disabled = false;
- }
- else {
+ // If sending is disabled by config, keep send button disabled
+ if (window.APP_CONFIG && window.APP_CONFIG.sendingEnabled === false) {
document.getElementById("sendButton").disabled = true;
+ } else {
+ if (fsmText != "") {
+ document.getElementById("sendButton").disabled = false;
+ } else {
+ document.getElementById("sendButton").disabled = true;
+ }
}
const selectedCategories = getSelectedGroupsCategories();
diff --git a/public/js/main.js b/public/js/main.js
index 22afe1c..992e171 100644
--- a/public/js/main.js
+++ b/public/js/main.js
@@ -5,6 +5,17 @@ const getVersion = async () => {
return version;
};
+const getConfig = async () => {
+ try {
+ const resp = await fetch('/api/config');
+ if (!resp.ok) return { success: false };
+ return resp.json();
+ } catch (e) {
+ console.error('Failed to load config', e && e.message);
+ return { success: false };
+ }
+};
+
const printVersionInNav = async () => {
document.getElementById("navVersion").text = await getVersion();
};
@@ -85,8 +96,23 @@ checkForRedirect();
window.onload = async () => {
printVersionInNav();
+
+ // load runtime config (DEV mode and sending enabled)
+ const cfg = await getConfig();
+ if (cfg && cfg.success && cfg.data) {
+ window.APP_CONFIG = cfg.data;
+ if (cfg.data.dev) {
+ const nd = document.getElementById('navDev');
+ if (nd) nd.style.display = 'block';
+ }
+ // If sending is disabled, disable send button to prevent user attempts
+ if (!cfg.data.sendingEnabled) {
+ const sendBtn = document.getElementById('sendButton');
+ if (sendBtn) sendBtn.disabled = true;
+ }
+ }
+
pageOnLoadFunctions();
- if (await isAdmin())
- document.getElementById("adminNavLink").style.display = "block";
+ if (await isAdmin()) document.getElementById("adminNavLink").style.display = "block";
};
diff --git a/public/login.html b/public/login.html
index 9b3c531..3011d92 100644
--- a/public/login.html
+++ b/public/login.html
@@ -9,7 +9,7 @@
-
+
Fullsend | SMS notification from the web
@@ -34,6 +34,9 @@
+ -
+ DEV MODE
+
-
diff --git a/public/no-access.html b/public/no-access.html
index 7b19aed..9b77f15 100644
--- a/public/no-access.html
+++ b/public/no-access.html
@@ -9,7 +9,7 @@
-
+
Fullsend | SMS notification from the web
@@ -40,6 +40,9 @@
+ -
+ DEV MODE
+
-
diff --git a/public/privacy.html b/public/privacy.html
index 01d13d3..58934d9 100644
--- a/public/privacy.html
+++ b/public/privacy.html
@@ -9,7 +9,7 @@
-
+
Fullsend | SMS notification from the web
@@ -40,6 +40,9 @@
+ -
+ DEV MODE
+
-
diff --git a/public/terms.html b/public/terms.html
index 9255bd6..b739fde 100644
--- a/public/terms.html
+++ b/public/terms.html
@@ -9,7 +9,7 @@
-
+
Fullsend | SMS notification from the web
@@ -40,6 +40,9 @@
+ -
+ DEV MODE
+
-
diff --git a/server.js b/server.js
index 769c277..9fd7a1d 100644
--- a/server.js
+++ b/server.js
@@ -203,6 +203,19 @@ app.get('/api/login', async (req, res) => {
}
});
+// Public config endpoint for client-side behavior toggles (DEV mode, sending enabled)
+app.get('/api/config', (req, res) => {
+ try {
+ const dev = String(process.env.DEV || '').toLowerCase() === 'true';
+ // If DEV is true, force sending disabled
+ const sendingEnabled = dev ? false : (String(process.env.SENDING_ENABLED || '').toLowerCase() === 'true');
+ res.send({ success: true, data: { dev, sendingEnabled } });
+ } catch (e) {
+ console.error('config endpoint failed', e && e.message);
+ res.status(500).send({ success: false });
+ }
+});
+
// Debug endpoint (no role enforcement) to inspect session info during development
app.get('/api/debug/session', async (req, res) => {
try {