Add a "moderation" key into the youtube websocket api


#1

This is probably more of a niche request, as in while I’d like it added I doubt many will have a use for this, other than what I’m trying to do (or similar). I will be abbreviating “Youtube Websocket API” as YWAPI (Say that out loud).

So within the botlogin.txt you have two YWAPI keys:

ytauth=HarrHarrHarrIBeAKey
ytauthro=HarrHarrHarrIBeAKeyToo

(Let’s not mention how it’s hard to know what each is for).

So the top one, ytauth, is used for the player, and if you use it in the YWAPI, it’s expected that you’re making your own player through the YWAPI calls. Obviously, this gives you full “control” to the player, since you’ll be making it on your end.

The bottom one, ytauthro, is used for the playlist. Using this key in the YWAPI will only give you “read” rights, as in you can view the playlist, Song Req list, and current playing.That being said, you can’t delete requested songs, or even skip the current playing.

This leads me to my suggestion… I would like a key, or the ability to use an existing key, so I can apply moderation to an already-opened YT player. Moderation as in: Steal Songs, Delete songs from song requests, skip now playing, so on. Basically everything that isn’t playing the song, and changing playlists.

Possible solution:
Allow ytauth to be used as a readkey, and depending on the context, allow it to act as a player or as the ‘moderator’. Such as, if you connect to the socket with ytauth=AuthHere it would act like normal, but if you connected with readauth=AuthHere, it wouldn’t give you the player functionality, just the abilities described above.

I’m sure this request makes little to no sense at this point, but I’m not sure how to word it better… so I’ll instead show the modifications I did to make it work on my end:

    if (jsonObject.has("authenticate")) {
        authenticated = jsonObject.getString("authenticate").equals(authString);
        sessionData.setAuthenticated(authenticated);
        sessionData.setPlayer(true);
        authResult(authenticated, webSocket);
        if (authenticated) {
            EventBus.instance().postAsync(new YTPlayerConnectEvent());
        }
        return;
    } 
    if (jsonObject.has("readauth")) {
        authenticated = jsonObject.getString("readauth").equals(authStringRO);
        sessionData.setAuthenticated(authenticated);
        sessionData.setPlayer(false);
        authResult(authenticated, webSocket);
        return;
    }
    // New code below this line
    if (jsonObject.has("modauth")) {
        authenticated = jsonObject.getString("modauth").equals(authStringRO);
        sessionData.setAuthenticated(authenticated);
        sessionData.setPlayer(false);
        sessionData.setModControl(true);// new Boolean to allow edits
        authResult(authenticated, webSocket);
        return;
    } 

More edits:

    } else if (jsonObject.has("deletesr") && (sessionData.isPlayer() || sessionData.getModControl())) {
        dataString = jsonObject.getString("deletesr");// notice how it's checking getModControl (the boolean from before) too
        EventBus.instance().postAsync(new YTPlayerDeleteSREvent(dataString));
    } else if (jsonObject.has("deletepl") && (sessionData.isPlayer() || sessionData.getModControl())) {
        dataString = jsonObject.getString("deletepl");
        EventBus.instance().postAsync(new YTPlayerDeletePlaylistByIDEvent(dataString));
    } else if (jsonObject.has("command") && (sessionData.isPlayer() || sessionData.getModControl())) {
        if (jsonObject.getString("command").equals("togglerandom")) {
            EventBus.instance().postAsync(new YTPlayerRandomizeEvent());
        } else if (jsonObject.getString("command").equals("skipsong")) {
            EventBus.instance().postAsync(new YTPlayerSkipSongEvent());
        } else if (jsonObject.getString("command").equals("stealsong")) {
            if (jsonObject.has("youTubeID")) {
                dataString = jsonObject.getString("youTubeID");
                EventBus.instance().postAsync(new YTPlayerStealSongEvent(dataString));
            } else {
                EventBus.instance().postAsync(new YTPlayerStealSongEvent());
            }
        } else if (jsonObject.getString("command").equals("songrequest")) {
            if (jsonObject.has("search")) {
                dataString = jsonObject.getString("search");
                EventBus.instance().postAsync(new YTPlayerSongRequestEvent(dataString));
            }
        } else {
            com.gmt2001.Console.err.println("YTWebSocketServer: Bad ['command'] request passed ["+jsonString+"]");
            return;
        }
    } else {
        com.gmt2001.Console.err.println("YTWebSocketServer: Unknown JSON passed ["+jsonString+"]");
        return;
    }

Obviously I can just edit that code back in each time I update, but that’s a tedious process. I’m aware the webpanel is designed for a single user, hence why I’m connecting through the YWAPI instead of through the panel itself.

Thanks for reading this mile-long suggestion.


#2

The idea behind the regular and read-only key is that the key can be exposed in a public fashion if not protected correctly. No one cares about a read-only key, people care about a key that can manipulate the player data (delete playlists, change volume, etc). The public read-only key sits right now, for users that host it, readable by anyone that uses the playlist/ endpoint. So, all I would need to do is visit your playlist/ endpoint, get the read-only key, write a little program that authorizes via the modauth - and I am free to delete your song requests and playlists. The writable key is protected by the webserver by an authentication mechanism and the file can only be read if the person authenticates. At that point they already have write access via the GUI, so having the ability to read the write-key is a moot point - you have already trusted them at this point.

That said, I am not sure I would be supportive of a key that is read-only that performs update/write operations. A new key would probably be the way to go if you wish to provide “multiple-access” tiers, assuming your service is using Twitch as an authentication point as well to verify their identity as a moderator or not.


#3

I understand those concerns, which is why I was hinting at using the existing ytauth key, the one that already obtains the write access and the like.

The twitch authentication is actually a good idea, and something I partially implemented into my website. I was working on the admin zone next, but that’s another story.

I’m actually using the key, and everything else, in a standalone Java application. Obviously I can’t “hide” my key within the program because of deobfuscators and other tools, but that’s why I’ve chosen to not put the key in the program. It’s loaded externally kind of like how the botlogin is. That way I can be free to distribute the tool, and if I want someone to have write access to my player I have to give them my configuration.

I guess if it was ever implemented you’d have to give a warning like “Be careful who you give this key to, as it grants management access to your youtube player” etc etc…


#4

But:

    // New code below this line
    if (jsonObject.has("modauth")) {
        authenticated = jsonObject.getString("modauth").equals(authStringRO);

That is the read-only key. Do you mean for that to be the authString instead?

You don’t have to do Twitch authentication obviously, but, that would at least make sure you know who is coming in, if that is desired. If not, then just a username/password is fine. We didn’t do such a thing on the current Panel because, well, it was meant for single-user use.

If you are using a standalone Java application, I recommend Jasypt. I use this in my Spring Boot applications so that my properties look like:

security.oauth2.client.clientId: ENC(YgVuSyP5ovrjI+xhZ+ZgRKphJYs5Am7+rOevj0FNKqTi07+0YaYZYg==)
security.oauth2.client.clientSecret: ENC(Hh1p7Pj5IWEknhzHbYqpTXNMerggfrmCuBndYK9OG9jD8ZTuq764Vg==)

#5

Yeah I believe I did. I threw in a quick copy-paste there because I wanted to demonstrate my example a bit better.

As for Jasypt, I’ll definitely have to look into that