SockChat — A SneedChat client for the command line - A lightweight standalone SneedChat client for the terminal, written in Go

  • 🐕 I am attempting to get the site runnning as fast as possible. If you are experiencing slow page load times, please report it.
Any plans for making an Android app that wraps SockChat inside a basic interface? It would be somewhat easier than running straight from Termux.
 
  • Thunk-Provoking
Reactions: y a t s
Any plans for making an Android app that wraps SockChat inside a basic interface? It would be somewhat easier than running straight from Termux.
I do have plans for a sort of API mode that external programs, such as custom UIs (perhaps a web UI or phone app), can use to access chat data and control some underlying features.

In theory, a universal locally hosted web UI would be the easiest for phone compatibility, but at that point you might as well use the normal site's chat. I'm eventually making the API mode regardless of this, but I'm a tad skeptical as to whether an official interface is worth adding to the project when the normal site chat already exists. That said, the API mode will (hopefully) make it very straightforward to make a simple third-party interface.

Consider using something like tmux with your Termux setup if you don't already. Tmux is excellent for things like clients that you leave running in the background, since you can just re-attach to it whenever. Another tip: Ctrl-U really helps with quickly clearing the input field, and is easily my most used terminal shortcut aside from Ctrl-C for a SIGINT.
 
Last edited:
Big update. The cookies you give the program will now work for as long the browser you took them from stays logged in.
nuh uh.png
This required the creation of 2 custom libraries (firebird, libkiwi) and was aided by the kind addition of some kiwiflare challenge data tags by our Ooperator. This is a huge step closer to simple credential-based login support.

If your existing config file has the .net domain, change it to the .st one for this to work. I didn't implement challenge forwarding yet. Tor is not supported yet due to a different anti-DDoS type that I haven't implemented a solver for.

Chat authentication depends on a short-lasting session token, xf_session. This session token doesn't affect whether your browser stays signed in to the site, but it's used for authentication as long as your current session is active. When this session token expires, the site will assign your browser a new one, based off other longer lasting account-related cookies you have set, when you load a new page on the site (e.g. the home page).

What I do here is solve the kiwiflare challenge, request the home page using the existing cookies the chat client is provided, and use the new xf_session cookie from the HTTP response headers to reconnect to chat and authenticate successfully.
 
Last edited:
Tor is not supported yet due to a different anti-DDoS type that I haven't implemented a solver for.
I thought the ooperator in chief changed Tor to use the same KiwiFlare as the main site when he did some Tor cleanup a while back. Well, the challenge page looks the same now at least.
 
  • Informative
Reactions: y a t s
I thought the ooperator in chief changed Tor to use the same KiwiFlare as the main site when he did some Tor cleanup a while back. Well, the challenge page looks the same now at least.
Looks like you're right. It's no longer haproxy-protection. Well, that saves me a fair bit of time lol.

Thanks for the heads up.

Edit: Had to push an update to fix a hard-coded domain in my solver lib. All good now.
 
Last edited:
  • Like
Reactions: slungus22
Important update. Cookies are now saved to the config file, so the program can be run in most cases without providing any command arguments. To save the cookies, edit your config.json file or pass them using the new --cookies="COOKIES_HERE" argument. Once they're saved, the program will save the newest ones to the config upon exit and hopefully manage the cookies without any user intervention required.
 
This required the creation of 2 custom libraries (firebird, libkiwi) and was aided by the kind addition of some kiwiflare challenge data tags by our Ooperator. This is a huge step closer to simple credential-based login support.
Is there a way to offer this solver in CLI form for use in other applications?

Right now for my chat bot I'm popping out a browser window and automatically logging into the forum whenever the session token expires which does work but is relatively resource intensive. With this I could get rid of Chromium entirely as it's trivial to POST the logon credentials to https://kiwifarms.st/login/login and save the cookies returned, it's just an XHR POST, the hard part was always Kiwiflare.

There's also an IRC bot I maintain that grabs URL titles and it's a bummer every time a Kiwi Farms link gets hit with "Just a moment..." so it would be cool to automatically solve the Kiwiflare challenges and serve people real titles.
 
  • Like
Reactions: y a t s
Is there a way to offer this solver in CLI form for use in other applications?

Right now for my chat bot I'm popping out a browser window and automatically logging into the forum whenever the session token expires which does work but is relatively resource intensive. With this I could get rid of Chromium entirely as it's trivial to POST the logon credentials to https://kiwifarms.st/login/login and save the cookies returned, it's just an XHR POST, the hard part was always Kiwiflare.

There's also an IRC bot I maintain that grabs URL titles and it's a bummer every time a Kiwi Farms link gets hit with "Just a moment..." so it would be cool to automatically solve the Kiwiflare challenges and serve people real titles.
Writing a front-end for the solver is very straightforward. The library is written so that you just request a challenge with it, start the solver workers, and then call the submit function once one is found. The submit function returns the new sssg_clearance cookie the server provides in response. You can always initialize a challenge object manually and then run the solve function on it if you want to skip the HTTP stuff.
 
Writing a front-end for the solver is very straightforward. The library is written so that you just request a challenge with it, start the solver workers, and then call the submit function once one is found. The submit function returns the new sssg_clearance cookie the server provides in response. You can always initialize a challenge object manually and then run the solve function on it if you want to skip the HTTP stuff.
Sorry sir but Go sucks and I refuse to write any so I ported your code to C#.
I didn't bother with parallelism as it solves within seconds even with a single worker, but I did implement the hash test using bit arrays instead for "technical correctness".

Thanks for the sample as there's no way I could've unscrambled the .js to figure out how it worked.
 
Sorry sir but Go sucks and I refuse to write any so I ported your code to C#.
I didn't bother with parallelism as it solves within seconds even with a single worker, but I did implement the hash test using bit arrays instead for "technical correctness".

Thanks for the sample as there's no way I could've unscrambled the .js to figure out how it worked.
lol glad I could help. It's just a sha256 variant of hashcash, so it's not super complex as long as you're not an IoT device :)

Edit: In case it helps, you can check for redirects to the kiwiflare challenge page by looking for a 203 status code in the http response when fetching any site page. This can save you from parsing the html if the challenge data isn't there.
 
Last edited:
  • Informative
Reactions: Harvey Danger
lol glad I could help. It's just a sha256 variant of hashcash, so it's not super complex as long as you're not an IoT device :)

Edit: In case it helps, you can check for redirects to the kiwiflare challenge page by looking for a 203 status code in the http response when fetching any site page. This can save you from parsing the html if the challenge data isn't there.
Yeah I've started logging the timings and it usually solves in less than 100 ms. Impressive what a modern CPU can do even with my shitty code and .NET's sometimes mediocre performance.

For me it was easier to check the validity of the token using /.sssg/api/check to pre-empt a potential challenge and solve it proactively. Kinda backwards to how a real browser would interact with the site but seems to work ok.

I've now implemented automated logins but no support for 2FA since you have to POST the TOTP in response to a challenge and I couldn't be bothered going to the effort as my bot doesn't use 2FA.

Code is here in case you want to do something similar for SockChat https://github.com/barelyprofession...er/KfChatDotNetBot/Services/KfTokenService.cs
Everything you need to automate the login form is in the <html> tag, data-csrf which you'll need to send alongside credentials, and data-logged-in for figuring out if a user is already logged in.

You'll see I have 2 checks for figuring out if a user successfully logged in. I found the 303 "See Other" response when watching the logon process using a real browser and implemented it around that initially but this didn't work as .NET HttpClient follows redirects by default. It's easy to disable that but I decided to just let it follow the redirect and check the page content instead so that way I know the chat token is definitely fresh.
 
For me it was easier to check the validity of the token using /.sssg/api/check to pre-empt a potential challenge and solve it proactively. Kinda backwards to how a real browser would interact with the site but seems to work ok.
Bear in mind that the additional HTTP request could slow you down a bit when server load is high.

I've now implemented automated logins but no support for 2FA since you have to POST the TOTP in response to a challenge and I couldn't be bothered going to the effort as my bot doesn't use 2FA.
Yeah, that's why I don't have simple credential login support yet. I don't think 2FA would be tough to handle, but I'm too busy to look into it any time soon.

You'll see I have 2 checks for figuring out if a user successfully logged in. I found the 303 "See Other" response when watching the logon process using a real browser and implemented it around that initially but this didn't work as .NET HttpClient follows redirects by default. It's easy to disable that but I decided to just let it follow the redirect and check the page content instead so that way I know the chat token is definitely fresh.
There are a number of different ways to check for valid session data. The Set-Cookie response header can tell you a lot about your cookie states; it's very handy.

For handling redirects, Go's http response structs contain the request data that was used to obtain that final response, and you can use RoundTripper hooks for more complex tasks.
.NET makes my brain sad, so idk, but perhaps they have something similar.
 
  • Like
Reactions: slungus22
After using that newer version of Sockchat, I noticed a few annoyances I would like to mention:
  1. The cookie refresh system is great, however it only works when switching chat room to General Chat (which requires ~20 posts to access). Whenever Sockchat loses connection and tries again, I cannot send any messages. If I type /join 1 (for refreshing the cookie) and then join back my previous channel, everything works as expected.
  2. The -help command doesn't seem to have the updated info.
  3. Whenever I try to pass a cookie via the command line, it doesn't save directly to the config.json file. Might be intentional though.
I'm writing a bash script for launching Sockchat (with extra arguments and stuff). Might post it here whenever I have something good to use.
 
After using that newer version of Sockchat, I noticed a few annoyances I would like to mention:
  1. The cookie refresh system is great, however it only works when switching chat room to General Chat (which requires ~20 posts to access). Whenever Sockchat loses connection and tries again, I cannot send any messages. If I type /join 1 (for refreshing the cookie) and then join back my previous channel, everything works as expected.
  2. The -help command doesn't seem to have the updated info.
  3. Whenever I try to pass a cookie via the command line, it doesn't save directly to the config.json file. Might be intentional though.
Thanks for the report :)
  1. I think I forgot to re-add tracking room changes through /join messages. Will fix.
  2. It needs updating along with the wiki. I'm still moving some config stuff around, so I don't have the structure finalized yet.
  3. Yeah it looks like this was caused by a variable scoping issue for a file descriptor. It will be fixed in the next version.
I did a bunch of refactoring and have to hammer out some final details, but a new version should be coming soon™.

I'm writing a bash script for launching Sockchat (with extra arguments and stuff). Might post it here whenever I have something good to use.
I base a majority of the arguments on values found in the config.json file. If you look at the file where I do arg parsing, you can see it temporarily overrides values in the Config object. If you have a common set of args that you pass to the program, you should be able to set it up through the config so that you can launch without any args.
 
Last edited:
Thanks for the report :)
  1. I think I forgot to re-add tracking room changes through /join messages. Will fix.
  2. It needs updating along with the wiki. I'm still moving some config stuff around, so I don't have the structure finalized yet. *not fixed yet*
  3. Yeah it looks like this was caused by a variable scoping issue for a file descriptor. It will be fixed in the next version.
I did a bunch of refactoring and have to hammer out some final details, but a new version should be coming soon™.
Done.
 
the windows x86 binary makes my windows defender angry
My build command (run on Arch Linux with latest updates) is GOOS=windows GOARCH=$arch go build -ldflags '-s -w' -trimpath -o build/sockchat_$arch.exe, where $arch is parsed from the output of go tool dist list. The flags I give are to strip paths and debug symbols from the binaries for privacy and to save some space. I have seen my earlier builds get flagged by some random AVs on VirusTotal despite me simply providing it whatever output the Go compiler gave me, and I'm not sure what the cause is.

Regardless, I commend your caution and invite you to build it yourself if you're feeling uneasy. It's really easy to do. Tbh, I'm surprised people trust the binaries provided by some random guy on a forum; that's why I didn't have them available for a long time.

Edit: Maybe some AVs don't like that there are features that allow it to spawn and control a tor process for the purposes of connecting to chat through it using torsocks. No clue if this is the case; just an idea I had.
 
Last edited:
Back