cerca icon indicating copy to clipboard operation
cerca copied to clipboard

RSS updates for private threads

Open decentral1se opened this issue 1 year ago β€’ 13 comments

Following https://github.com/cblgh/cerca/pull/66.

We now know that private threads are just excluded from the RSS feed. However, this potentially most juicy and interesting aspect of the forum deserves some RSS love! How can we do this while maintaining privacy?

One idea: separate rss feed with private updates which is only enabled via some config knob. This feed must then be protected by additional http basic auth. This could be implemented by cerca itself but probably most are proxying and $web_server can handle it?

The motivation is to keep forum users up to date on both public and private discussions via RSS.

decentral1se avatar Aug 21 '24 11:08 decentral1se

Another alternative: Logged-in users can visit a route to generate their own private RSS feed.

The randomly generated feed url is stored in the database and related to the user who generated it, acting as an access token for the private rss feed. When a request comes in for the route responsible for handling private rss feeds, the database checks "do i have it in my database?" if yes, then the result is returned as an rss feed with all posts included. If no, then pursue the same behaviour as with requests that have been throttled for being too eager.

What this enables: when a user is removed, their read access to the private feed can also be removed by removing the row containing their generated route.

This begs the question of where to present the route though, and I'm starting to think there are enough of these little pieces now to introduce a /profile route that gathers functionality for:

  • reset your own password
  • change your username?
  • generate private rss feed
  • (later) list xx most recent threads you have participated in, linking to your latest post in each thread

cblgh avatar Aug 21 '24 15:08 cblgh

Sounds legit! Actually this was also a thing discussed in the PMC chat with a tale about how some Wordpress (plugin?) which implements private feeds with cryptic URLs.

If you have spoons to lay out a little game plan I can follow again, I'm all for taking a stab at this. At least the feed part, if that can go first? Or I tag in after you lay some groundwork? I'm easy.

decentral1se avatar Aug 22 '24 06:08 decentral1se

Or even simpler: same idea but you only have to visit the regular rss route while logged in & it will redirect you to yr private route? Not yet sure which is soundest :)

edit: demangled my email response lmao

cblgh avatar Aug 22 '24 08:08 cblgh

Mullin' it over πŸ€”

Also, interesting: https://daringfireball.net/2005/02/feed_authentication

decentral1se avatar Aug 22 '24 10:08 decentral1se

If you have spoons to lay out a little game plan I can follow again, I'm all for taking a stab at this. At least the feed part, if that can go first? Or I tag in after you lay some groundwork? I'm easy.

definitely! i'll have it done before the weekend has come and gone again πŸ™ agree that the feed part can go first! i can try to sort out the profile bits & bobs afterwards :]

Also, interesting: https://daringfireball.net/2005/02/feed_authentication

ty! good note about the basic auth scheme, as the author of a very simple rss reader i was biased against it due to my program not having any modals to prompt users for auth details X)

cblgh avatar Aug 22 '24 15:08 cblgh

This is very exciting! (greetings from pmc chat)

Regarding http basic auth vs no auth. I've been trying to think about what could be the pros and cons and there is not a clear winner. Ultimately it boils down to trusting (or not) the software where the URL will be landing (from casually sharing a private feed URL without auth, to using a URL with username:password on local or remote RSS client).

Even if it feels a bit less elegant, I am tempted to lean towards adding http basic auth as the better way, simply because, ultimately, if this concerns private parts of a forum, I suppose there must be valid reasons for these parts of the forum to remain as private as possible?

320x200 avatar Aug 22 '24 21:08 320x200

@320x200 heyo! good points. ideally i'd want the basic auth to be self-contained within cerca so that the cerca binary is all you need. luckily i've already played around with basic auth for another project!

https://github.com/cblgh/mould/blob/main/server.go#L53-L81

d1: dump still to come, but i think we could do what i was thinking originally but in a basic auth fashion?

instead of passing the randomly generated token as part of the url path, we could instead interpret the token as the password portion of the basic auth. to make things easy for people to copy, we can output the link to the generated private rss feed as

http[s]://rss:<generated-token>@<forum-domain>/rss`

i.e. rss is the username, and the generated token is the password, and we keep the rss route unchanged and amend its routine to check for basic auth information Γ  la the linked-in snippet above. that way, if the auth checks out, we flip the switch on which threads to list in the feed i.e. listing all threads, and not only public threads. and if it doesn't check out then we just return the public-only rss?

note for pmc: basic auth details are sent unencrypted (base64 lol), so if you don't force https (which i understand some permacomputing projects shy away from) you'll run into the same concern as before

cblgh avatar Aug 23 '24 09:08 cblgh

note for pmc: basic auth details are sent unencrypted (base64 lol), so if you don't force https (which i understand some permacomputing projects shy away from) you'll run into the same concern as before

Thanks for thinking ahead! True, we have some concerns regarding defaulting everything to https. With that said, internet is scary place, so we will probably do the same as for the wiki, namely leave the choice to the visitor whether they want to browse as http or https, and only enforce https (via a simple Nginx redirect) for things that require authentication.

320x200 avatar Aug 23 '24 14:08 320x200

@decentral1se the promised dump, with a late sunday evening twist! tbf i think the easiest thing to do would be to just use basic auth for the actual username and password of the user? i don't know how sound it is though. if we don't go that route, below is an outline for how to generate a private rss feed that can be accessed by username and an access token using basic auth. it is functionally similar to username & passwords except only grants access to the private rss feed

but to be honest, i really haven't landed on whether the below approach is better than just letting users send their full creds to the server via basic auth. full creds could leak depending on what the rss software looks like, whereas the access token only gives partial access (a list of all thread names). yet there's a lot of code duplication below and a slight hacky vibe i can't quite shake. open to iterating & ideating if you concur on the slightly off-vibe!


crypto/crypto.go: you will want to use this function to generate the access token crypto.GeneratePassword()

database/database.go:

  • db.createTables(): create a new database table by adding the following element to createTable()'s internal slice:
/* this is currently only used for generating a personal rss feed that also includes private threads */
  `CREATE TABLE IF NOT EXISTS access_token (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    accessid INTEGER NOT NULL,
    tokenhash TEXT NOT NULL,

    FOREIGN KEY (accessid) REFERENCES users(id)
  );`
  • create a new function to retrieve the hash of the access token for a given username func (d DB) GetTokenHash(username string) (string, error)
    • this is basically mimicking db.GetPasswordHash) except with the following sql statementβ€”which i haven't tried! you might need to tweak / confirm the inner join:
stmt := `SELECT a.tokenhash FROM
access_token a 
INNER JOIN users u 
ON a.accessid = u.id
where u.name = ?`
  • create a new function that generates an access token for the given user. basically, copy ResetPassword() and inline the call to db.UpdateUserPasswordHash(), changing the relevant places to operate on table access_token instead

server/server.go:

  • introduce some new route GeneratePrivateRSSFeedRoute() only accessible by logged in users which generates an access token for the logged in user and returns the string https://<username>:<accessToken>@<forum-domain> as the data for an instance of GenericMessageData (search for GenericMessageData to see how it's used)

GenerateRSS()

  • refactor function variable includePrivateThreads to instead be one of the function's parameters

type RequestHandler struct

  • introduce variable privateRSSFeed, setting it in both places and in the same way as h.rssFeed is set except using the new bool parameter for GenerateRSS() (i.e. includePrivateThreads = true)

RSSRoute()

  • check the request for basic auth credentials, if they don't exist, return h.rssFeed as normal
  • if credentials do exist, check them against the database using the new function you create GetTokenHash(credentialUsername) which gets the related accessToken for that username if it exists
    • look at server.LoginRoute() and the use of crypto.ValidatePasswordHash for how to compare the received credential against the retrieved hash of the access token
    • if the credentials match (username is correct, stored hash of the access matches credential accessToken) then return the new h.privateRSSFeed

cblgh avatar Aug 25 '24 19:08 cblgh

@cblgh nice, tysm! I think this looks fine personally. Given that we don't really know how good RSS clients will take care of creds, it seems good to separate this from the default user password? I have a pretty large stack of TODOs atm but hoping to get to this from next week. Lemme know if you settle on this design or decide to re-work it 😌

decentral1se avatar Aug 27 '24 05:08 decentral1se

@decentral1se great! i'll take the extra moments to really mull it over :]

cblgh avatar Aug 27 '24 09:08 cblgh

Will be AFK for until end of September so more time to mull over πŸ˜† Can dive into this in October unless anyone gets there before me ✌️ The current proposal still reads well imho.

decentral1se avatar Sep 10 '24 10:09 decentral1se

cheers! the mulling did prove useful and, in the end, i found myself willing to accept the approach i suggested above. fewer unexpected issues that will be run into, feels like

fwiw bit of a busy period right now too so let me know if things should be prioritized or not (for example). otherwise i see myself looping back to things in october when you have a bit more time as well πŸ™

cblgh avatar Sep 10 '24 16:09 cblgh

See https://github.com/cblgh/cerca/issues/70#issuecomment-2477374636

~~To complicate matters, we are now using Nginx HTTP basic auth for privacy πŸ˜…~~

~~So, the https://USERNAME:PASSWORD@<CERCA-URL> trick is already being used to bypass the Nginx auth and not a possible private thread token auth πŸ™ƒ~~

~~I know we're still in the formation stages of this but do we see any way to "toggle" this functionality? I am still prepared to carry out the implementation, if so.~~

~~So, people can make use of this "token" feed auth (built-in) OR private feed posts are included in the main feed and "external" auth is used.~~

~~It seems like a config option could be used.~~

[rss]
# default is token
# 'external' means you bring your own auth
private = "token" # OR "external"

decentral1se avatar Nov 14 '24 15:11 decentral1se

To complicate matters, we are now using Nginx HTTP basic auth for privacy πŸ˜…

super curious to hear the rationale of this / how this came about!

So, the https://USERNAME:PASSWORD@<CERCA-URL> trick is already being used to bypass the Nginx auth and not a possible private thread token auth πŸ™ƒ

yeh, in my last post i came to terms with moving away from that anway. it would have unanticipated consequences for users that forget their password and have it changed; they would discover later on that their rss feed wasn't loading anymore and not really know why.

So, people can make use of this "token" feed auth (built-in) OR private feed posts are included in the main feed and "external" auth is used.

ah interesting, so let me phrase how i read your suggestion (based on PMC's developing needs):

add a configurable toggle to include private posts in the forum's single rss feed. is that right?

cblgh avatar Nov 14 '24 18:11 cblgh

Yes, you got it!

But now actually reflecting on this, I think maybe we should put my latest request to the side. Things are moving a lot and we're experimenting... I think I should try to open less "fresh" requests πŸ™ƒ My apologies.

In one sense, this is "solved" for us because we're just blocking entry completely via HTTP basic auth and only using public threads for RSS updates. That is also "RSS updates for private threads" πŸ™ˆ

decentral1se avatar Nov 14 '24 20:11 decentral1se

no worries! in my case i'm always happy to jam and think things through with ya 🀘

cblgh avatar Nov 14 '24 20:11 cblgh

Won't be needing this anymore!

decentral1se avatar Dec 29 '24 16:12 decentral1se