Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSS updates for private threads #70

Open
decentral1se opened this issue Aug 21, 2024 · 13 comments
Open

RSS updates for private threads #70

decentral1se opened this issue Aug 21, 2024 · 13 comments

Comments

@decentral1se
Copy link
Contributor

decentral1se commented Aug 21, 2024

Following #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.

@cblgh
Copy link
Owner

cblgh commented Aug 21, 2024

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

@decentral1se
Copy link
Contributor Author

decentral1se commented Aug 22, 2024

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.

@cblgh
Copy link
Owner

cblgh commented Aug 22, 2024 via email

@decentral1se
Copy link
Contributor Author

Mullin' it over 🤔

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

@cblgh
Copy link
Owner

cblgh commented Aug 22, 2024

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)

@320x200
Copy link

320x200 commented Aug 22, 2024

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?

@cblgh
Copy link
Owner

cblgh commented Aug 23, 2024

@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

@320x200
Copy link

320x200 commented Aug 23, 2024

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.

@cblgh
Copy link
Owner

cblgh commented Aug 25, 2024

@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

@decentral1se
Copy link
Contributor Author

decentral1se commented Aug 27, 2024

@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 😌

@cblgh
Copy link
Owner

cblgh commented Aug 27, 2024

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

@decentral1se
Copy link
Contributor Author

decentral1se commented Sep 10, 2024

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.

@cblgh
Copy link
Owner

cblgh commented Sep 10, 2024

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 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants