From a291e4626aef4588325ac476e5d8f99718b09108 Mon Sep 17 00:00:00 2001 From: Kristy Fournier <124598538+kristy-fournier@users.noreply.github.com> Date: Sat, 12 Jul 2025 22:09:18 -0400 Subject: [PATCH 01/12] added options --- Client/index.html | 21 +++++++++++++++++++-- Client/scripts.js | 8 ++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Client/index.html b/Client/index.html index 6012ac4..23420b7 100644 --- a/Client/index.html +++ b/Client/index.html @@ -81,13 +81,30 @@ changes visibility with JS-->

Volume of the music

-
+

Share the remote:

-

Version 1.0.2

+

Admin Settings

+

Note: Admin password must have been set from the server

+
+

Admin Password:

+

Enter to use admin restricted functions

+ +
+
+

Fine action control:

+

A check means that action is avalible to everyone

+
+
+
+
+
+
+
+

PartyJukebox is under an AGPLV3 liscense. You can access the source code here.

diff --git a/Client/scripts.js b/Client/scripts.js index a63ee01..10bbd5f 100644 --- a/Client/scripts.js +++ b/Client/scripts.js @@ -192,6 +192,14 @@ async function checkSettings(skipServer=false) { qrCodeGenerate() document.getElementById("alerttimetextbox").value = alertTime partyButtonState = document.getElementById("partymode-button").innerHTML; + checksforadmin = document.getElementById("admincheckholder") + // temporary + for (let i in checksforadmin.children) { + if (i.type == "checkbox") { + i.checked = true; + } + } + //ping the server here x = await getFromServer({setting: "getsettings"}, "settings"); if (!(skipServer) || partyButtonState=="N/A") { if (x["partymode"] == false) { -- 2.49.1 From 26e8e937852a72198c10c11773a0e616e4db5018 Mon Sep 17 00:00:00 2001 From: Kristy Fournier <124598538+kristy-fournier@users.noreply.github.com> Date: Fri, 18 Jul 2025 18:31:02 -0400 Subject: [PATCH 02/12] Fixed adminperms labels --- Client/index.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Client/index.html b/Client/index.html index 23420b7..7d14a89 100644 --- a/Client/index.html +++ b/Client/index.html @@ -98,11 +98,11 @@ changes visibility with JS-->

Fine action control:

A check means that action is avalible to everyone

-
-
-
-
-
+
+
+
+
+

PartyJukebox is under an AGPLV3 liscense. You can access the source code here.

-- 2.49.1 From ea0380e3eb4c16c9dd00213f3c46688f1eb737d4 Mon Sep 17 00:00:00 2001 From: Kristy Fournier <124598538+kristy-fournier@users.noreply.github.com> Date: Fri, 18 Jul 2025 18:31:22 -0400 Subject: [PATCH 03/12] changed a for loop to fix for testing --- Client/scripts.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Client/scripts.js b/Client/scripts.js index 10bbd5f..7ee24de 100644 --- a/Client/scripts.js +++ b/Client/scripts.js @@ -192,11 +192,11 @@ async function checkSettings(skipServer=false) { qrCodeGenerate() document.getElementById("alerttimetextbox").value = alertTime partyButtonState = document.getElementById("partymode-button").innerHTML; - checksforadmin = document.getElementById("admincheckholder") + let nodeList = document.getElementById("admincheckholder").children // temporary - for (let i in checksforadmin.children) { - if (i.type == "checkbox") { - i.checked = true; + for (let i=0; i Date: Fri, 18 Jul 2025 18:31:46 -0400 Subject: [PATCH 04/12] Added base of password system and check for adding a song --- Server/webbyBits.py | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/Server/webbyBits.py b/Server/webbyBits.py index 614e1b4..d8fe771 100644 --- a/Server/webbyBits.py +++ b/Server/webbyBits.py @@ -8,7 +8,20 @@ parser=argparse.ArgumentParser(description="Options for the Webby Bits") # this is no longer needed assuming my file works correctly with the generator # parser.add_argument('-d','--directory',help="Directory of the song files (make sure this matches the directory used for the databaseGenerator)", default="./sound/") parser.add_argument('-p','--port',help="Port to host on, not the same as the web (client) port",default='19054') -portTheUserPicked=parser.parse_args().port +parser.add_argument('-a','--admin',help="Add an admin password to be used in the client. DO NOT use a password you use elsewhere",default="") +args = parser.parse_args() +portTheUserPicked=args.port +ADMIN_PASS = args.admin +if not(ADMIN_PASS): + ADMIN_PASS = None +# True = everyone, False = admin only. Change in client while in use. +controlPerms = { + "PP":True, + "SK":True, + "AS":True, + "PM":True, + "VOL":True +} fileofDB = sql.connect("songDatabase.db") songDatabase = fileofDB.cursor() @@ -119,9 +132,16 @@ def settingsControl(): elif recieveData["setting"] == "partymode-toggle": partyMode = not(partyMode) return "200" + elif recieveData["setting"] == "perms": + if ADMIN_PASS == recieveData["password"] and ADMIN_PASS: + controlPerms = recieveData["admin"] + return "200" + else: + return "401" + elif recieveData["setting"] == "getsettings": # probably should have made this a different request type or something but it works - x = {"partymode":partyMode,"volume":player.audio_get_volume()} + x = {"partymode":partyMode,"volume":player.audio_get_volume(),"admin":controlPerms} return x else: return "400" @@ -154,8 +174,17 @@ def searchSongDB(): @app.route("/songadd", methods=["POST"]) def songadd(): recieveData=request.get_json(force=True) - queueSong(recieveData['song']) - return "200" + if ADMIN_PASS and ADMIN_PASS == recieveData['password']: + # Pass exists and is correct + queueSong(recieveData['song']) + return "200" + elif ADMIN_PASS and not(controlPerms["AS"]): + # Pass exists, or this action isn't restricted + return "401" + else: + # No pass + queueSong(recieveData['song']) + return "200" @app.route("/playlist", methods=["POST"]) def getPlaylist(): global songNext -- 2.49.1 From f41255e45653934e43a3017185d0da9983d3c0a0 Mon Sep 17 00:00:00 2001 From: Kristy Fournier <124598538+kristy-fournier@users.noreply.github.com> Date: Fri, 18 Jul 2025 19:21:21 -0400 Subject: [PATCH 05/12] added server side password verification to everything that needs it --- Server/webbyBits.py | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/Server/webbyBits.py b/Server/webbyBits.py index d8fe771..22a84c5 100644 --- a/Server/webbyBits.py +++ b/Server/webbyBits.py @@ -16,11 +16,11 @@ if not(ADMIN_PASS): ADMIN_PASS = None # True = everyone, False = admin only. Change in client while in use. controlPerms = { - "PP":True, - "SK":True, - "AS":True, - "PM":True, - "VOL":True + "PP":True, #done + "SK":True, #done + "AS":True, #done + "PM":True, #done + "VOL":True #done } fileofDB = sql.connect("songDatabase.db") @@ -111,34 +111,48 @@ def playerControls(): recieveData=request.get_json(force=True) if recieveData["control"] != None: if recieveData["control"] == "play-pause": - player.pause() - return "200" + if ADMIN_PASS == recieveData['password'] or not(ADMIN_PASS) or controlPerms["PP"]: + player.pause() + return "200" + else: + return "401" elif recieveData["control"] == "skip": - skipNow = True - # print(str(player.get_state())) - return "200" + if ADMIN_PASS == recieveData['password'] or not(ADMIN_PASS) or controlPerms["SK"]: + skipNow = True + return "200" + else: + return "401" else: return "400" @app.route("/settings", methods=['POST']) def settingsControl(): + global controlPerms # set the volume and partymode global partyMode global player recieveData = request.get_json(force=True) if recieveData["setting"] == "volume": - volumePassed = player.audio_set_volume(int(recieveData["level"])) - return {"volumePassed":volumePassed} + if ADMIN_PASS == recieveData['password'] or not(ADMIN_PASS) or controlPerms["VOL"]: + volumePassed = player.audio_set_volume(int(recieveData["level"])) + return {"volumePassed":volumePassed} + else: + return "401" elif recieveData["setting"] == "partymode-toggle": - partyMode = not(partyMode) - return "200" + if ADMIN_PASS == recieveData['password'] or not(ADMIN_PASS) or controlPerms["PM"]: + partyMode = not(partyMode) + return "200" + else: + return "401" elif recieveData["setting"] == "perms": + print(ADMIN_PASS) + print(recieveData["password"]) if ADMIN_PASS == recieveData["password"] and ADMIN_PASS: + #if an adminpass doesn't exist these perms can never be changed controlPerms = recieveData["admin"] return "200" else: return "401" - elif recieveData["setting"] == "getsettings": # probably should have made this a different request type or something but it works x = {"partymode":partyMode,"volume":player.audio_get_volume(),"admin":controlPerms} -- 2.49.1 From 1910b30acc32ea6979ed8a171b4d01df8e73e1fe Mon Sep 17 00:00:00 2001 From: Kristy Fournier <124598538+kristy-fournier@users.noreply.github.com> Date: Fri, 18 Jul 2025 20:13:18 -0400 Subject: [PATCH 06/12] everything but the auto-updating settings should be working and also skipping isnt working on the playlist page --- Client/index.html | 4 ++-- Client/scripts.js | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Client/index.html b/Client/index.html index 7d14a89..8bd1d0a 100644 --- a/Client/index.html +++ b/Client/index.html @@ -92,7 +92,7 @@ changes visibility with JS-->

Admin Password:

Enter to use admin restricted functions

- +

Fine action control:

@@ -101,7 +101,7 @@ changes visibility with JS-->


-
+

diff --git a/Client/scripts.js b/Client/scripts.js index 7ee24de..07d5d73 100644 --- a/Client/scripts.js +++ b/Client/scripts.js @@ -1,5 +1,6 @@ -let ip -let alertTime = 2 +let ip; +let alertTime = 2; +let adminPass = ""; async function alertText(text="Song Added!") { alertbox = document.getElementById("alert"); alertbox.innerHTML = text; @@ -10,8 +11,11 @@ async function alertText(text="Song Added!") { } // a lot of this is kinda waffly because i was trying to get // it to return the right stuff and javascript is asyrcronouse (boo) -async function getFromServer(bodyInfo, source="") { +async function getFromServer(bodyInfo, source="",password=adminPass) { try{ + if (bodyInfo != null) { + bodyInfo["password"] = password; + } const response = await fetch("http://"+ip+"/"+source, { method: "POST", body: JSON.stringify(bodyInfo), @@ -20,10 +24,15 @@ async function getFromServer(bodyInfo, source="") { } }); const data = await response.json(); + if (data == "401") { + alertText("error: Admin restricted action") + } return await data; } catch(e) { if (e == "TypeError: Failed to fetch"){ alertText("error: Can't Connect to Server (is the ip set?)") + } else if(e == "") { + } else { alertText("error: " + e) } @@ -309,6 +318,22 @@ function toggleDark(e) { } } +function adminPassEnter(e) { + if (e.key == "Enter") { + e.preventDefault(); + adminPass=document.getElementById("adminpasswordbox").value + alertText("Admin Password Updated") + } +} +function submitPerms() { + let tempData = {} + tempData["PP"] = document.getElementById("playpausesettingcheckbox").checked + tempData["SK"] = document.getElementById("skipsongsettingcheckbox").checked + tempData["AS"] = document.getElementById("addsongsettingcheckbox").checked + tempData["PM"] = document.getElementById("partymodesettingcheckbox").checked + tempData["VOL"] = document.getElementById("partymodesettingcheckbox").checked + getFromServer({"setting":"perms","admin":tempData},"settings") +} let optionslist = [] @@ -344,6 +369,8 @@ document.getElementById("go-search").addEventListener('click', function(){search document.getElementById("songsearch").addEventListener('keydown', function(e){searchSongsEnter(e)}); document.getElementById("iptextbox").addEventListener('keydown', function(e){ipSetEnter(e)}); document.getElementById("alerttimetextbox").addEventListener('keydown', function(e){alertTimeEnter(e)}); +document.getElementById("adminpasswordbox").addEventListener('keydown',function(e){adminPassEnter(e)}); +document.getElementById("admincheckholder").addEventListener('click',function(){submitPerms()}); document.getElementById("partymode-button").addEventListener('click',function(){controlButton("pm")}) //sets the fact that clicking a song needs to return its id to the function to find it document.getElementById("songlist").addEventListener('click', function(e){checkWhatSongWasClicked(e)}); -- 2.49.1 From 36c2286b41a12f0735554e419a9a5cc9a3809ccc Mon Sep 17 00:00:00 2001 From: Kristy Fournier <124598538+kristy-fournier@users.noreply.github.com> Date: Fri, 3 Oct 2025 15:32:14 -0400 Subject: [PATCH 07/12] Update readme.md --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index e63bcbd..59f555b 100644 --- a/readme.md +++ b/readme.md @@ -65,6 +65,7 @@ From left to right: - The currently playing song is identified, and has the duration listed - The play-pause button toggles playing - The skip button goes to the next track + - *No "previous" button is a design decision (It's a feature not a bug)* - The search button opens the search screen (pictured) - The settings button (top right) opens the settings menu - Server IP allows you to change the ip that the site connects to -- 2.49.1 From 1733a485b4ab874750e219f4db9626c073adc922 Mon Sep 17 00:00:00 2001 From: Kristy Fournier <124598538+kristy-fournier@users.noreply.github.com> Date: Fri, 3 Oct 2025 17:26:12 -0400 Subject: [PATCH 08/12] 99% done also added some new comments and notes about future design changes --- Client/scripts.js | 33 ++++++++++++++++++++++++++------- Server/webbyBits.py | 25 ++++++++++++++----------- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/Client/scripts.js b/Client/scripts.js index 07d5d73..2f8130d 100644 --- a/Client/scripts.js +++ b/Client/scripts.js @@ -222,6 +222,16 @@ async function checkSettings(skipServer=false) { document.getElementById("partymode-button").innerHTML = "Off"; } document.getElementById("volumerange").value = parseInt(x["volume"]) + + // do the admin checkboxes here + // seemingly i almost finished it last time, dunno why i stopped here + // like as far as i can tell this is the last step + let currentAdminPerms = x["admin"]; + document.getElementById("addsongsettingcheckbox").checked = currentAdminPerms["AS"]; + document.getElementById("skipsongsettingcheckbox").checked = currentAdminPerms["SK"]; + document.getElementById("playpausesettingcheckbox").checked = currentAdminPerms["PP"]; + document.getElementById("partymodesettingcheckbox").checked = currentAdminPerms["PM"]; + document.getElementById("volumechangesettingcheckbox").checked = currentAdminPerms["VOL"]; } async function generateVisualPlaylist(conditions="") { @@ -325,14 +335,20 @@ function adminPassEnter(e) { alertText("Admin Password Updated") } } -function submitPerms() { +async function submitPerms() { let tempData = {} - tempData["PP"] = document.getElementById("playpausesettingcheckbox").checked - tempData["SK"] = document.getElementById("skipsongsettingcheckbox").checked - tempData["AS"] = document.getElementById("addsongsettingcheckbox").checked - tempData["PM"] = document.getElementById("partymodesettingcheckbox").checked - tempData["VOL"] = document.getElementById("partymodesettingcheckbox").checked - getFromServer({"setting":"perms","admin":tempData},"settings") + tempData["PP"] = document.getElementById("playpausesettingcheckbox").checked; + tempData["SK"] = document.getElementById("skipsongsettingcheckbox").checked; + tempData["AS"] = document.getElementById("addsongsettingcheckbox").checked; + tempData["PM"] = document.getElementById("partymodesettingcheckbox").checked; + tempData["VOL"] = document.getElementById("partymodesettingcheckbox").checked; + let returncode = await getFromServer({"setting":"perms","admin":tempData},"settings"); + if (returncode === "401") { + // just so that the checkboxes don't change if you click without the + // (I know i could do this better but this is good enough for now) + // okay this actually doesn't work but i have to go eat dinner + checkSettings(); + } } let optionslist = [] @@ -350,6 +366,8 @@ document.getElementById("settings-mode").style.display = "none"; document.getElementById("volumerange").onchange = async function() { let returnValue = await getFromServer({setting:"volume",level:this.value}, "settings") if (returnValue["volumePassed"] !=0) { + // i forgot about this, i had to do this because it confused the crap out of me one time + // vlc doesn't let you change the volume of nothing, which makes sense if you think about it alertText("Nothing is playing") document.getElementById("volumerange").value = -1 } @@ -378,6 +396,7 @@ document.getElementById("songlist").addEventListener('click', function(e){checkW let tempWidth = document.getElementById('controls').clientWidth; document.getElementById("controls").style.marginLeft = "-"+String(parseInt(tempWidth/2))+"px"; // document.getElementById("darkmode-button").addEventListener('click',function(){toggleDark()}) + //for my use case (my immediate family), they dont know how to set an ip //using this allows the creator of the link for, a qr code for example, to set the ip before distributing the code, and it would all work smoothly //example (http://192.168.1.100:8000/?ip=192.168.1.100:19054 sets the ip to the same host at the default port) diff --git a/Server/webbyBits.py b/Server/webbyBits.py index 22a84c5..fb81d9f 100644 --- a/Server/webbyBits.py +++ b/Server/webbyBits.py @@ -10,7 +10,11 @@ parser=argparse.ArgumentParser(description="Options for the Webby Bits") parser.add_argument('-p','--port',help="Port to host on, not the same as the web (client) port",default='19054') parser.add_argument('-a','--admin',help="Add an admin password to be used in the client. DO NOT use a password you use elsewhere",default="") args = parser.parse_args() + + portTheUserPicked=args.port +#Just a note that the return code "401" as of now is used to mean "you don't have the password" +#This is not great design, and the whole "returning string codes" thing is something to add to the todo list ADMIN_PASS = args.admin if not(ADMIN_PASS): ADMIN_PASS = None @@ -36,7 +40,7 @@ elif "/" in soundLocation: soundLocation += "/" else: soundLocation += "\\" -print(soundLocation) +#print(soundLocation) #Create Virtual table for searching songDatabase.execute("DROP TABLE virtualSongs;") songDatabase.execute("CREATE VIRTUAL TABLE virtualSongs USING fts5(filename, title, artist, art, length);") @@ -58,7 +62,7 @@ player = fakeplayer.media_player_new() # for client side volume to work as well as possible, set system volume to 100 and control in app player.audio_set_volume(100) app = Flask(__name__) -# because you are posting from another domain to this one, you need CORS +# because you are POSTing from another domain to this one, you need CORS CORS(app) def queueSong(song): @@ -124,6 +128,8 @@ def playerControls(): return "401" else: return "400" + else: + return "400" @app.route("/settings", methods=['POST']) def settingsControl(): @@ -145,8 +151,8 @@ def settingsControl(): else: return "401" elif recieveData["setting"] == "perms": - print(ADMIN_PASS) - print(recieveData["password"]) + # print(ADMIN_PASS) + # print(recieveData["password"]) if ADMIN_PASS == recieveData["password"] and ADMIN_PASS: #if an adminpass doesn't exist these perms can never be changed controlPerms = recieveData["admin"] @@ -188,17 +194,14 @@ def searchSongDB(): @app.route("/songadd", methods=["POST"]) def songadd(): recieveData=request.get_json(force=True) - if ADMIN_PASS and ADMIN_PASS == recieveData['password']: - # Pass exists and is correct + if (ADMIN_PASS and ADMIN_PASS == recieveData['password']): + # Pass exists and is correct, or it's not restricted queueSong(recieveData['song']) return "200" - elif ADMIN_PASS and not(controlPerms["AS"]): + else: # Pass exists, or this action isn't restricted return "401" - else: - # No pass - queueSong(recieveData['song']) - return "200" + @app.route("/playlist", methods=["POST"]) def getPlaylist(): global songNext -- 2.49.1 From 76971ea75e6b8e76b54594f77f387da383ce5e62 Mon Sep 17 00:00:00 2001 From: Kristy Fournier <124598538+kristy-fournier@users.noreply.github.com> Date: Fri, 3 Oct 2025 18:51:12 -0400 Subject: [PATCH 09/12] Done adding admin password Just gotta do documentation --- Client/scripts.js | 30 +++++++++++++++++------------- Client/styles.css | 8 ++++++++ Server/webbyBits.py | 18 ++++++++++-------- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/Client/scripts.js b/Client/scripts.js index 2f8130d..02ac217 100644 --- a/Client/scripts.js +++ b/Client/scripts.js @@ -1,6 +1,8 @@ let ip; let alertTime = 2; let adminPass = ""; +const ERR_NO_ADMIN = "401"; // gonna use this later to refactor + async function alertText(text="Song Added!") { alertbox = document.getElementById("alert"); alertbox.innerHTML = text; @@ -25,12 +27,12 @@ async function getFromServer(bodyInfo, source="",password=adminPass) { }); const data = await response.json(); if (data == "401") { - alertText("error: Admin restricted action") + alertText("Error: Admin restricted action") } return await data; } catch(e) { if (e == "TypeError: Failed to fetch"){ - alertText("error: Can't Connect to Server (is the ip set?)") + alertText("Error: Can't Connect to Server (is the ip set?)") } else if(e == "") { } else { @@ -224,8 +226,6 @@ async function checkSettings(skipServer=false) { document.getElementById("volumerange").value = parseInt(x["volume"]) // do the admin checkboxes here - // seemingly i almost finished it last time, dunno why i stopped here - // like as far as i can tell this is the last step let currentAdminPerms = x["admin"]; document.getElementById("addsongsettingcheckbox").checked = currentAdminPerms["AS"]; document.getElementById("skipsongsettingcheckbox").checked = currentAdminPerms["SK"]; @@ -302,8 +302,12 @@ async function generateVisualPlaylist(conditions="") { } async function submitSong(songid) { - getFromServer({song: songid}, "songadd") - alertText("Added to Queue") + let returncode = await getFromServer({song: songid}, "songadd"); + if(returncode == ERR_NO_ADMIN) { + // right now the error is alerted in getFromServer, maybe will change that + } else { + alertText("Added to Queue"); + } } function checkWhatSongWasClicked(e) { itemId = e.srcElement.id; @@ -335,7 +339,7 @@ function adminPassEnter(e) { alertText("Admin Password Updated") } } -async function submitPerms() { +async function submitPerms(e) { let tempData = {} tempData["PP"] = document.getElementById("playpausesettingcheckbox").checked; tempData["SK"] = document.getElementById("skipsongsettingcheckbox").checked; @@ -343,11 +347,11 @@ async function submitPerms() { tempData["PM"] = document.getElementById("partymodesettingcheckbox").checked; tempData["VOL"] = document.getElementById("partymodesettingcheckbox").checked; let returncode = await getFromServer({"setting":"perms","admin":tempData},"settings"); - if (returncode === "401") { - // just so that the checkboxes don't change if you click without the - // (I know i could do this better but this is good enough for now) - // okay this actually doesn't work but i have to go eat dinner - checkSettings(); + if (returncode == ERR_NO_ADMIN) { + // if you aren't allowed to check the box then toggle it again + // its not perfect if you spam click, but it gets the point across to the user + let clickedBox = e.srcElement; + clickedBox.checked = !clickedBox.checked; } } @@ -388,7 +392,7 @@ document.getElementById("songsearch").addEventListener('keydown', function(e){se document.getElementById("iptextbox").addEventListener('keydown', function(e){ipSetEnter(e)}); document.getElementById("alerttimetextbox").addEventListener('keydown', function(e){alertTimeEnter(e)}); document.getElementById("adminpasswordbox").addEventListener('keydown',function(e){adminPassEnter(e)}); -document.getElementById("admincheckholder").addEventListener('click',function(){submitPerms()}); +document.getElementById("admincheckholder").addEventListener('click',function(e){submitPerms(e)}); document.getElementById("partymode-button").addEventListener('click',function(){controlButton("pm")}) //sets the fact that clicking a song needs to return its id to the function to find it document.getElementById("songlist").addEventListener('click', function(e){checkWhatSongWasClicked(e)}); diff --git a/Client/styles.css b/Client/styles.css index 803c5df..a6c4cdf 100644 --- a/Client/styles.css +++ b/Client/styles.css @@ -177,6 +177,14 @@ h4 { border-bottom: 0; } +.settings > .item > h2 { + margin-bottom: 4px; +} + +.settings > .item > p { + margin-top: 0px +} + .versionNumber { font-size: 8px; font-style: italic; diff --git a/Server/webbyBits.py b/Server/webbyBits.py index fb81d9f..c10a04b 100644 --- a/Server/webbyBits.py +++ b/Server/webbyBits.py @@ -13,8 +13,10 @@ args = parser.parse_args() portTheUserPicked=args.port -#Just a note that the return code "401" as of now is used to mean "you don't have the password" -#This is not great design, and the whole "returning string codes" thing is something to add to the todo list +# Just a note that the return code "401" as of now is used to mean "you don't have the password" +# This is not great design, and the whole "returning string codes" thing is something to add to the todo list +# I mean returning 200 when no return is necesary i think is fine but we'll see +ERR_NO_ADMIN = "401" ADMIN_PASS = args.admin if not(ADMIN_PASS): ADMIN_PASS = None @@ -119,13 +121,13 @@ def playerControls(): player.pause() return "200" else: - return "401" + return ERR_NO_ADMIN elif recieveData["control"] == "skip": if ADMIN_PASS == recieveData['password'] or not(ADMIN_PASS) or controlPerms["SK"]: skipNow = True return "200" else: - return "401" + return ERR_NO_ADMIN else: return "400" else: @@ -143,13 +145,13 @@ def settingsControl(): volumePassed = player.audio_set_volume(int(recieveData["level"])) return {"volumePassed":volumePassed} else: - return "401" + return ERR_NO_ADMIN elif recieveData["setting"] == "partymode-toggle": if ADMIN_PASS == recieveData['password'] or not(ADMIN_PASS) or controlPerms["PM"]: partyMode = not(partyMode) return "200" else: - return "401" + return ERR_NO_ADMIN elif recieveData["setting"] == "perms": # print(ADMIN_PASS) # print(recieveData["password"]) @@ -158,7 +160,7 @@ def settingsControl(): controlPerms = recieveData["admin"] return "200" else: - return "401" + return ERR_NO_ADMIN elif recieveData["setting"] == "getsettings": # probably should have made this a different request type or something but it works x = {"partymode":partyMode,"volume":player.audio_get_volume(),"admin":controlPerms} @@ -200,7 +202,7 @@ def songadd(): return "200" else: # Pass exists, or this action isn't restricted - return "401" + return ERR_NO_ADMIN @app.route("/playlist", methods=["POST"]) def getPlaylist(): -- 2.49.1 From 189cafd08a30d83fe429f78d5b993117051bcb49 Mon Sep 17 00:00:00 2001 From: Kristy Fournier <124598538+kristy-fournier@users.noreply.github.com> Date: Fri, 3 Oct 2025 19:03:49 -0400 Subject: [PATCH 10/12] Readme update Should be good to be pushed to main now --- Client/scripts.js | 2 +- readme.md | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Client/scripts.js b/Client/scripts.js index 02ac217..46d1a54 100644 --- a/Client/scripts.js +++ b/Client/scripts.js @@ -347,7 +347,7 @@ async function submitPerms(e) { tempData["PM"] = document.getElementById("partymodesettingcheckbox").checked; tempData["VOL"] = document.getElementById("partymodesettingcheckbox").checked; let returncode = await getFromServer({"setting":"perms","admin":tempData},"settings"); - if (returncode == ERR_NO_ADMIN) { + if (returncode == ERR_NO_ADMIN || returncode == null) { // if you aren't allowed to check the box then toggle it again // its not perfect if you spam click, but it gets the point across to the user let clickedBox = e.srcElement; diff --git a/readme.md b/readme.md index e63bcbd..0fa7206 100644 --- a/readme.md +++ b/readme.md @@ -28,6 +28,7 @@ webbyBits.py * *If getting images, this process may take a long time with a large amount of mp3 files* 4. Run `webbyBits.py` * *The port can be customized at runtime using* `-p portNumber` *as an atribute* + * *You can add an admin password at runtime with* `-a AdminPass` *as an atribute* You can now connect with the client and use the app as normal. \ *Make sure you have turned down/off any other apps that might make noise or notification sounds* \ @@ -57,6 +58,15 @@ These are specific details on each section of the app, and how to use them - Uses port 19054 by default - `--port (port)` changes the port for that run - The default port can be changed in the file + - Running with `--admin (admin password)` sets an admin password for moderation on the client + - Anyone who knows the admin password can enter it on the client and change the abilities of any non-admin users (for example to limit skipping) + - The total set of features that can be restricted is + - Skip track + - Play-pause toggle + - Add track + - Partymode toggle + - Change volume + - When this argument is left out (or empty string) the admin features aren't used, and everyone can do everything ### Client: ![image](./Screenshot_MAIN.png) \ -- 2.49.1 From d24aca7f3948f624d01dd1bf8daa685bea56ff3a Mon Sep 17 00:00:00 2001 From: Kristy Fournier <124598538+kristy-fournier@users.noreply.github.com> Date: Sun, 5 Oct 2025 09:02:48 -0400 Subject: [PATCH 11/12] made very clear passwords are not secure --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 0fa7206..9a79055 100644 --- a/readme.md +++ b/readme.md @@ -29,6 +29,7 @@ webbyBits.py 4. Run `webbyBits.py` * *The port can be customized at runtime using* `-p portNumber` *as an atribute* * *You can add an admin password at runtime with* `-a AdminPass` *as an atribute* + * ***NOTE: Do not reuse ANY password for this, it is 100% unsecure. The best option is just a random string you write down once*** You can now connect with the client and use the app as normal. \ *Make sure you have turned down/off any other apps that might make noise or notification sounds* \ @@ -59,6 +60,7 @@ These are specific details on each section of the app, and how to use them - `--port (port)` changes the port for that run - The default port can be changed in the file - Running with `--admin (admin password)` sets an admin password for moderation on the client + - ***Note: Do not reuse a password, consider this like making whatever this string is public, no security is guaranteed*** - Anyone who knows the admin password can enter it on the client and change the abilities of any non-admin users (for example to limit skipping) - The total set of features that can be restricted is - Skip track -- 2.49.1 From 86fde793056e12928479aa7186870c85a8eba337 Mon Sep 17 00:00:00 2001 From: Kristy Fournier <124598538+kristy-fournier@users.noreply.github.com> Date: Sun, 5 Oct 2025 09:04:24 -0400 Subject: [PATCH 12/12] make VERY CLEAR the password feature is not secure --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 9a79055..a54546e 100644 --- a/readme.md +++ b/readme.md @@ -30,6 +30,7 @@ webbyBits.py * *The port can be customized at runtime using* `-p portNumber` *as an atribute* * *You can add an admin password at runtime with* `-a AdminPass` *as an atribute* * ***NOTE: Do not reuse ANY password for this, it is 100% unsecure. The best option is just a random string you write down once*** + * This is intended for protecting certain features for small closed events, not for public security You can now connect with the client and use the app as normal. \ *Make sure you have turned down/off any other apps that might make noise or notification sounds* \ -- 2.49.1