Sneedforo

  • 🐕 I am attempting to get the site runnning as fast as possible. If you are experiencing slow page load times, please report it.
I have written complex permission systems before (namely for Infinity Next), but without OOP I'm not 100% on what to do for it. There is no Rust solution in a crate.
Rust has classes and other such containers though, how are you without OOP?

Also, if you are without OOP you could still allocate and populate boolean values in each user's data where each element is a yes/no permission for a certain action. For the sanity of the site staff you could store these permission booleans in a vector so that they can be easily changed when you add or remove areas of the site, and then pair those permission vectors with a vector of strings storing the labels for each permission.

If you still want to have permission groups, you could create lists of permissions (which in this case would be arrays of ints corresponding to the position of certain elements in the permissions vectors, i.e. [2,6,127] for the 2nd, 6th, and 127th perms as a group) and then have a function which checks whether a user has all of the permissions on those lists, and a function which sets all the perms on a list to either true or false.

Sorry if that's not a good solution, I'm not a web developer, but thought I'd chime in since I have some experience with C++ and Rust.
 
Last edited:
you can look at my progress on the permission stuff here

In XenForo, as it stands, we have 148 different permissions. There's no bitmask that can fit all that. The actual solution I'm working on is more complicated.

There will be three 64b masks for yes/no/never and each permission group will be one of those. I'll simply that with a CRUD example. Each bracket is a permission group, and each permission is Create|Read|Update|Delete.

Mask Post Chat
Yes [0000][0000]
No. [0000][0000]
Nvr [0000][0000]


This is basically set math that you were taught in school but never had a use for.

Here's how it computes. Say that you're in two groups with different permissions. In the first group, you are a registered user with full permissions in chat. In the second group, you are chatbanned.

Mask Post Chat Post Chat Post Chat
Yes [1111][1111] [0000][0000]
No. [0000][0000] + [0000][0000] = [1111][0100]
Nvr [0000][0000] [0000][1011]


Meaning, you can only read chat.

If you're wondering why there's a No row but also a Never, it's because sometimes we have permissions that are revoked but then regained.

For instance: the board Talk to Staff. A registered user can see posts, but in Talk to Staff they can't read other people's posts. Staff can. That would look like this:

Mask Post TTS Mod
Yes [1111] [0000] [0100]
No. [0000] + [0100] + [0000] = [1111] (for staff) [1011] (for users)
Nvr [0000] [0000] [0000]


This gets really complicated when you have sub-boards, group and user specific permissions, etc. That's why I'm writing unit tests. If I fuck anything up I had right before the system will notice it before I do.

When the forum starts, the software will pull all the permissions into memory in this sort of format. That way, when a user accesses a page, it should be very fast to figure out what he can and cannot do in real time without caching in the database.

(wrote this out mostly for my own benefit)
 
If you're wondering why there's a No row but also a Never
Actually I'm wondering why there is a Yes and a No.
It seems to me that for any single permission in a single group, the value can be only one of Yes|No|Never at a time, right? In that case why not just say:

Code:
pub struct PermissionGroupValues {
    yesno: u64,
    never: u64,
}
If the "never" bit is set at a given position in the mask, then we don't care about the yes/no bit at that position and we always interpret it as NEVER.
If the "never" bit is not set, then the interpretation is YES if the "yesno" bit is 1, NO if it's 0.

Then:
Code:
impl PermissionGroupValues {
    // Combines group values laterally.
    // Explicit YES permissions override explicit NO permissions.
    fn join(&self, left: &PermissionGroupValues) -> PermissionGroupValues {
        // Combine NEVER
        let never = self.never | left.never;
        // Combine YESNO
        let yesno = (self.yesno | left.yesno);
        PermissionGroupValues { yesno, never, }
    }
}

And so on. Yes and No are mutually exclusive, Never is handled separately since it can override either.
Then the "vertical join" is just an AND on .yesno rather than an OR.
 
Actually I'm wondering why there is a Yes and a No.
Because, as I explained and as is present in the code, the no is actually a revoke.

Code:
// A single Instruction output by the tokenizer.
pub enum PermissionValue {
    YES = 1,     // Grants permission
    DEFAULT = 0, // Unset permission
    NO = -1,     // Removes any existing YES permission
    NEVER = -2,  // Never permitted, cannot be re-permitted.
}

DEFAULT (NO)
+ YES (USER ROLE)
- NO (RESOURCE) (not NEVER because we're rescinding a YES, not banning)
+ YES (USER ROLE, RESOURCE)

A NEVER is as it says. if you're banned from posting, you can NEVER post.
 
No. Rust is just self-aware about how silly it is being a language that's 12 years old that still breaks compatibility every major compiler release.
This is actually very affirming and making me less mad.

😂

I'm on my third try with node js here. I broke down and tried it with CYGWIN. There are literally three functions that I want to play with in here, and I am stuck on the two-line install instruction.

The set math, the boundary condition (basically the distinction between no and never) and the idea of multi layered permissions tied to resources, all good. Understood. I liked the comment about user_id going directly to the DB table. Clean and good. A bunch of the routine session instructions are the ones I want to understand RN.

This is a discrete optimization problem. I can't see all of it yet.
 
Last edited:
No. Rust is just self-aware about how silly it is being a language that's 12 years old that still breaks compatibility every major compiler release.
i've tried programming in rust before, it's syntax and features are a clusterfuck and i just stopped
 
you can look at my progress on the permission stuff here

In XenForo, as it stands, we have 148 different permissions. There's no bitmask that can fit all that. The actual solution I'm working on is more complicated.

There will be three 64b masks for yes/no/never and each permission group will be one of those. I'll simply that with a CRUD example. Each bracket is a permission group, and each permission is Create|Read|Update|Delete.

Mask Post Chat
Yes [0000][0000]
No. [0000][0000]
Nvr [0000][0000]


This is basically set math that you were taught in school but never had a use for.

Here's how it computes. Say that you're in two groups with different permissions. In the first group, you are a registered user with full permissions in chat. In the second group, you are chatbanned.

Mask Post Chat Post Chat Post Chat
Yes [1111][1111] [0000][0000]
No. [0000][0000] + [0000][0000] = [1111][0100]
Nvr [0000][0000] [0000][1011]


Meaning, you can only read chat.

If you're wondering why there's a No row but also a Never, it's because sometimes we have permissions that are revoked but then regained.

For instance: the board Talk to Staff. A registered user can see posts, but in Talk to Staff they can't read other people's posts. Staff can. That would look like this:

Mask Post TTS Mod
Yes [1111] [0000] [0100]
No. [0000] + [0100] + [0000] = [1111] (for staff) [1011] (for users)
Nvr [0000] [0000] [0000]


This gets really complicated when you have sub-boards, group and user specific permissions, etc. That's why I'm writing unit tests. If I fuck anything up I had right before the system will notice it before I do.

When the forum starts, the software will pull all the permissions into memory in this sort of format. That way, when a user accesses a page, it should be very fast to figure out what he can and cannot do in real time without caching in the database.

(wrote this out mostly for my own benefit)
My opinion:

1. Not all permissions can be represented with "CRUD". It seems like you will scale out of "CRUD".

2.You have a database, it is much easier to just store the information clearly there than to fiddle with bits.


A good way (like I said before) is to have user groups, allowed actions, and a column connecting groups to user actions. Then for blocks maybe a whole another column that you check during actions.

Using your example, to chat ban someone, just assign a "blocked from chat" section in the block table, and implement it in the code.

For the "talk to staff", add a feature that only allows certain groups to post in a sub forum, while letting other groups post and read. Then assign people to those groups.

For user specific permissions , have another column in the user table alongside the groups column, with individual permissions. Then check both during endpoints.

SQL is fast if you use it in a key-value like manner. Which is very much possible with this method. Maybe i will submit proof of concept as PR but gitea is closed to new signups.
 
My opinion:

1. Not all permissions can be represented with "CRUD". It seems like you will scale out of "CRUD".

2.You have a database, it is much easier to just store the information clearly there than to fiddle with bits.


A good way (like I said before) is to have user groups, allowed actions, and a column connecting groups to user actions. Then for blocks maybe a whole another column that you check during actions.

Using your example, to chat ban someone, just assign a "blocked from chat" section in the block table, and implement it in the code.

For the "talk to staff", add a feature that only allows certain groups to post in a sub forum, while letting other groups post and read. Then assign people to those groups.

For user specific permissions , have another column in the user table alongside the groups column, with individual permissions. Then check both during endpoints.

SQL is fast if you use it in a key-value like manner. Which is very much possible with this method. Maybe i will submit proof of concept as PR but gitea is closed to new signups.
CRUD was the simple example. I understood the example to be the set of possible states for each permission action. The relationships between sets of actions and the resources/other objects that they hook to are what interests me from the optimization end. But I can't figure out the set of functions that open the session and call the user permission table(s) from the database. I think there are three.

This has the capability to scale really, really well. But I am worried about the implied dependencies in those built in functions, they mostly seem to live in "src/middleware" and might not be changeable. I dislike this part of interface design. These packages always add constraints. But the resource types and database configuration here are more flexible than I am used to. So that's why this is fun for me 😂

(I'm very sorry if I am being stupid, I'm excited about this for reasons that have nothing to do with this project. But all the feedback I get here is very helpful and I appreciate it.)
 
1. Not all permissions can be represented with "CRUD". It seems like you will scale out of "CRUD".
It's an example bro. I said 146 permissions.

2.You have a database, it is much easier to just store the information clearly there than to fiddle with bits.
no it's not you fucking idiot because what the fuck am I supposed to do? run a query for every single permission check on the page every single time it's loaded? that still doesn't work because FORUM PERMISSIONS are STACKED. You have permissions per user, per group, per resource per user and per group, and per sub-resource per user per group. you cannot fucking store this as a finalized permission unless you are going to store a row for every single user on the site - which still requires somehow calculating finalized permission masks.

I'm legit about to just lock the thread, nobody even reads what I write. i posted the code. do you see a single reference to crud?

like what an incredibly arrogant opinion. "just use sql for everything bro, ever think of that?" fuck off
 
ok status report

the forum permission stuff is here:
it's all global level still, I am not decided yet on how I want to make per-resource permissions but the code can do that already once I know how I want to organize it.

What I have been working on instead is a chatroom. @CrunkLord420 did a lot of the Actix work already to get a basic chat system working but now I am taking that and building on it.

The chat for XenForo we use was written by me. It's mostly isolated from the rest of the application and what few integrations it does have (@'ing people leaves a notification in their alerts, etc) are not really important. What is important is that the chat is very shitty because it's AJAX/PHP based.

So for the last two days I've been working on something sneaky. I have a way to take the XF session cookie, read the Redis cache where active sessions are stored, and then pull user info from the MySQL database.

Using this, I have managed to authenticate myself in a test app.

Code:
Session id: 1
Session: XfSession { id: 1, username: "admin", avatar_date: 0 }
Chat Started
Someone joined
In room "Main"

1654018435553.png


I have a super rudimentary chat where I can send myself messages between tabs. Now, I can also authenticate myself. I can flesh this out to look like KF chat very easily from where I'm standing at now.

What this means is that within the next week or two I might have something usable that will work for both the site right now and the new forum software in the future. If this works I can probably shave about a billion HTTP requests off the site each month while providing something way more responsive than what we have now.
 
I have a super rudimentary chat where I can send myself messages between tabs.
Are you using http requests, or have you gone with websockets? I had to write a rudimentary IM/chat system for a project a couple of years back and ended up with a godawful hybrid of both, because clients and their bizarre requirements are a bitch. I would have gone with a pure memesocket implementation if I'd had the choice.
 
  • Informative
Reactions: Dork Of Ages
Look forward to seeing the new chat in action.

Thought I would throw an idea out, which will probably be terrible for technical reasons but...I'd be interested to know if it was possible.

Would it be possible to store NO ip data at all, apart from if someone gets ip banned? Might actually be an incentive for people to not shit up the place. Your privacy is only mildly compromised if you are a dick and warrant it.
 
  • Thunk-Provoking
Reactions: Dork Of Ages
ok status report

the forum permission stuff is here:
it's all global level still, I am not decided yet on how I want to make per-resource permissions but the code can do that already once I know how I want to organize it.

What I have been working on instead is a chatroom. @CrunkLord420 did a lot of the Actix work already to get a basic chat system working but now I am taking that and building on it.

The chat for XenForo we use was written by me. It's mostly isolated from the rest of the application and what few integrations it does have (@'ing people leaves a notification in their alerts, etc) are not really important. What is important is that the chat is very shitty because it's AJAX/PHP based.

So for the last two days I've been working on something sneaky. I have a way to take the XF session cookie, read the Redis cache where active sessions are stored, and then pull user info from the MySQL database.

Using this, I have managed to authenticate myself in a test app.

Code:
Session id: 1
Session: XfSession { id: 1, username: "admin", avatar_date: 0 }
Chat Started
Someone joined
In room "Main"

View attachment 3339374

I have a super rudimentary chat where I can send myself messages between tabs. Now, I can also authenticate myself. I can flesh this out to look like KF chat very easily from where I'm standing at now.

What this means is that within the next week or two I might have something usable that will work for both the site right now and the new forum software in the future. If this works I can probably shave about a billion HTTP requests off the site each month while providing something way more responsive than what we have now.
And it's gonna have the Discord-like layout of chatrooms on the left with notification blips and all that? Say what you want about Discord, but they nailed the layout game.
 
And it's gonna have the Discord-like layout of chatrooms on the left with notification blips and all that? Say what you want about Discord, but they nailed the layout game.
I don't see the point of writing a whole chat platform from scratch when you can host a Matrix server with Element which is almost a discord clone in UI.

Also reject Sneedforo, return to MyBB
 
Back