Contributing on GitHub requires JS and that creates challenges and some are discouraged

Hasn’t been maintained for 10 months, and currently doesn’t build.

I guess the question is, would you use it?

Well, Sourcehut does have CSS, albeit very basic.

It’s also a MASSIVE PAIN to self-host. Been trying to two days now, and keep getting 500 Errors on both the bare metal and containerised versions (which hadn’t been touched for more than 2 years, and needed to be heavily gutted and patched…)…

2 Likes

Hasn’t been maintained for 10 months, and currently doesn’t build.

You can file a bug report :stuck_out_tongue:

There is also Log - stagit - static git page generator - marked as “rocks” by suckless.org.

For bug reporting there is also bugzilla. It works without JS on other project sites.

Well, Sourcehut does have CSS, albeit very basic.

I just said it worked without CSS (read: blocked explicitly).

2 Likes

Already done :smiley:

Stagit is great for generating static pages of git repos, but you can’t really do anything with them. They’re not interactive, and wouldn’t let you push commits.

That it does. That…it…does… :sunglasses:


Well, the SourceHut I’ve got up and running looks nothing like https://sr.ht/:frowning:

I’ll keep trying…

3 Likes

Already done :smiley:

Good!

Stagit is great for generating static pages of git repos, but you can’t really do anything with them. They’re not interactive, and wouldn’t let you push commits.

Why would anyone push commits through web and not through local git tools?

Well, the SourceHut I’ve got up and running looks nothing like https://sr.ht/:frowning:

Interesting. Their site is obviously used by many. I wonder how they do it.

I’ll keep trying…

The potential advantage of SH is that (if it works) it may solve multiple problems - source hosting/dev platform, mailing list, etc.

1 Like

I agree, but some people enjoy tedium :stuck_out_tongue:

1 Like

The way their READMEs are written, it seems they’re meant for people who can “fill in the blanks” where they fall short. A lot of steps are missing, and unless you’ve been hosting things for years, you wouldn’t know to do those steps…

To be fair, they have said their software is still in alpha, so I’m sure this will get fixed once they’ve sorted everything out…

It seems to be built for scale.

Why they used to support installation on multiple OSes, and now, for some reason, only support Alpine Linux (lightweight Docker containers, maybe…?) isn’t actually clear…

The way it’s structured is you have several Go applications that bind to certain ports on your machine (or multiple machines), depending on what functions you want to have:

  • meta
    • User accounts
    • Access control
    • Customer Billing (if you really want that)
  • git
    • All the git stuff
  • hg
    • Mercurial integration (I think…)
  • lists
    • Mailing Lists
      • Requires an SMTP server (which I have, but happy to use whatever)
  • builds
    • CI/CD “stuff”
      • Requires QEMU
  • todo
    • Issues and bug tracker
  • man
    • Wiki
  • pages
    • Static pages hosting
  • paste
    • Pastebin
  • hub
    • Repository (or “project”, as they call it) indexing and organisation
      • Requires a cron daemon

They all seem to use a common config directory, including the common config.ini file.


I have set up all of them in a testing lab, and they all load (so far…), but the redirects across different Go applications (and corresponding ports) is driving me mental…

The resulting websites are full of redirects to all those various Go applications with some kind of authentication mechanism (it looks like session cookies).

I will provide an onion address for the lab once I solve all the Internal Server Errors (500) caused by failing redirects.


Also, @qubist, just putting it out there. With purely static pages being loaded, all the code is being executed by the server. This would include things like password hashing.

Without any kind of client-side code execution, anyone wanting to log into SourceHut via the web interface would essentially be sending a POST request:

<form method="POST" action="/login">
      <div class="form-group">
        <input type="hidden" name="_csrf_token" value="57c04912ab3272c9a64fe05313857afe191a77e28f45a491092bff52d3d84466077b02cd011df723149efedc0a5151080efa28cc8920d90392ed0bc220856196"><label for="username">Username</label>
        <input type="text" name="username" id="username" class="form-control " required="" autocomplete="username" autofocus="">
        
      </div>
      <div class="form-group">
        <label for="password">Password</label>
        <input type="password" name="password" id="password" class="form-control " required="" autocomplete="current-password">
        
      </div>
      <input type="hidden" name="return_to" value="">
      
      <button class="btn btn-primary pull-right" type="submit">
        Log in <span class="icon icon-caret-right " aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 192 512"><path d="M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z"></path></svg>
</span>
      </button>
      <p>
        <a href="http://meta.sr.ht.qubes-os.org/forgot">Forgot your password?</a>
      </p>
    </form>

This would mean that the browser would be sending plaintext passwords to the server, as can be seen by the POST request below:

POST /login HTTP/1.1
Host: meta.sr.ht.qubes-os.org
Content-Length: 188
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Origin: http://meta.sr.ht.qubes-os.org
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://meta.sr.ht.qubes-os.org/login
Accept-Encoding: gzip, deflate, br
Cookie: session=.eJwFwcsNAlEIBdBepgIeg3xsZgIDd2OiiRo3xt4957sd5-uJ4_24zf348HbdYjkNBFZgKFTSwDstiqa0QXXbiMJcEgjqVLGkOndXQ5R6QKmEG141imaRORO6RnVWqTSnOyddvC06OcPWag4d4337_QExQCtv.Z84rNA.qA3TpnpOq6kUh_oJ8Kixyh3G-k0
Connection: keep-alive

_csrf_token=9180ef4f7bf2f6f64a7f230109d0a7efbdd7e46f784aff90da647a0bc3867f9b689f60b42df8bbe6fd244ecaf61e66e1b64d2a882a058d79da2a9711d296e723&username=admin&password=plaintextpassword&return_to=

So, unless I’m wrong on this, this wouldn’t fly with most people, especially if they’re already paranoid about JavaScript and CSS… :confused:

3 Likes

The way their READMEs are written, it seems they’re meant for people who can “fill in the blanks” where they fall short.

The same applies to parts of Qubes docs as well.

Also, @qubist, just putting it out there. With purely static pages being loaded, all the code is being executed by the server.

Well, this is the job of the server - to serve pages to clients.

This would mean that the browser would be sending plaintext passwords to the server, as can be seen by the POST request below:

Plain text over TLS - all the difference in the world.

BTW, it is the same for GitHub login.

Speaking of docs and security, compare all this to qubes-os.org - Cloudflare MITM decrypts all traffic, thus contradicting the philosophy of infrastructure distrust and the claim of ‘As a project, we focus on securing endpoints instead of attempting to secure “the middle”…’

1 Like

Just expressing moderate concern for the fact that you’re giving the server your plaintext password, instead of running some client-side JavaScript to hash it before sending it over.

So if you’re happy with this, then I guess there’s no issue.

That site doesn’t really deal with any sensitive information, so from another viewpoint, you could technically call that “distrust of infrastructure”, in a sense.

Most certainly not in the sense you believe, but I can see how they made that decision…


Is there any chance of getting you to try it out yourself, and see what I did wrong?

1 Like

Just expressing moderate concern for the fact that you’re giving the server your plaintext password, instead of running some client-side JavaScript to hash it before sending it over.

I don’t understand your concern. The server will hash the received password and compare it with a local hash. It will not store it as plain text. What makes client-side hashing more secure? And secure from what exactly? (assuming TLS)

That site doesn’t really deal with any sensitive information, so from another viewpoint, you could technically call that “distrust of infrastructure”, in a sense.

How is instruction on how to get, install and use an OS not sensitive information? How does the visitor know what site he deals with? Suppose a rogue page tricks a random visitor to enter sensitive info, still claiming the connection is HTTPS. - He won’t know it, you know it. What is even worse - Cloudflare fingerprints users.

Is there any chance of getting you to try it out yourself, and see what I did wrong?

Unfortunately that chance is very small, as I am overloaded with lots of stuff. I may try if I find some time but can’t promise when.

1 Like

Ok, then go ahead and type your password into my website, and we’ll see if my server “stores it as plain text” or not. Go on. Don’t be shy :sunglasses:

Where do you think the server gets that “local hash” from in the first place?

Servers will do exactly what they are told, whatever that may be.

I’m sorry, but this caught me off-guard, and I really did not expect “the server will not store the plaintext password that you just voluntarily gave it, because…it just won’t, ok…?”.

I quote from your StackExchange link:

This answer isn’t really right. It highlights the vulnerability of a naïve approach to client-side hashing. It is certainly true that if the server does no hashing at all and just stores the value that the client sends, this would be no better than storing plaintext passwords. But the simple solution is to hash at both the client and the server. And with this simple solution in place we gain one significant advantage: the cost of resource-intensive password hashing can be shifted from the server to the client, and likely cranked up further than the server might be able to support.

  • The client does it’s own hashing/ecrypting/signing of “whatever is entered in the text box” to ensure that it’s in a specific format while in transit
    • If it’s intercepted in transit, even if TLS/HTTPS is poorly implemented/broken/spoofed/hijacked, that means the snoopers have something “less useful/reversible” than a plaintext password
  • When it reaches the server, the server hashes it again (with the same method, or a different one), and stores that instead of the plaintext password
    • The server never ever gets the plaintext password, because it starts off with a hash anyway
    • The network infrastructure, even if HTTPS is broken, never gets a plaintext password
    • If the server is breached for whatever reason (physical seizure, remote exploit, curious/bored sysadmin, they sold the hardware and “forgot to wipe the drives”, who knows…), then all they will see is the double-hashed values

Surely you’d agree that there’s a valid reason for doing it this way, at least over blindly sending a server a plaintext password, with no guarantee that they “didn’t store in plaintext”…

Those are all valid points. What would you suggest to rectify/mitigate them?

Potentially a signing key on some sort of distributed blockchain, making the website non-fungible, maybe?

It would nice after all this complaining in this thread, we could all be part of the solution. Hopefully some free time comes up so you can try and throw Sourcehut inside a VM and try it out :slight_smile:

3 Likes

Ok, then go ahead and type your password into my website, and we’ll see if my server “stores it as plain text” or not. […]

This doesn’t answer the questions.

Where do you think the server gets that “local hash” from in the first place?

Servers will do exactly what they are told, whatever that may be.

So does JS code sent by that same server to be executed by your browser. The essential difference is that the latter runs on your machine and opens the door to lots of mischief.

I’m sorry, but this caught me off-guard, and I really did not expect “the server will not store the plaintext password that you just voluntarily gave it, because…it just won’t, ok…?”.

Sorry about the confusion. I am not familiar with your background. I guess I am too used to doing that right that I simply assume that in 2025 the server must hash it and not store it as plain text. (e.g. PCI DSS compliance would actually require that, so would the “secure by design” stuff in GDPR, etc).

Of course, nothing prevents the backend from doing the wrong thing but it all comes down to what you are protecting and from what. Hence my questions which you did not answer.

I quote from your StackExchange link: […]

What you quote is not an accepted answer to the question but someone’s comment. If you have read the answers, you would have seen that practically all recommended server-side hashing with explanation why.

  • The client does it’s own hashing/ecrypting/signing of “whatever is entered in the text box” to ensure that it’s in a specific format while in transit

You don’t know (read: you don’t verify) what the client does. The server can send you any JS and your client will run it automatically.

  • If it’s intercepted in transit, even if TLS/HTTPS is poorly implemented/broken/spoofed/hijacked, that means the snoopers have something “less useful/reversible” than a plaintext password

If your TLS is not reliable, then anything delivered through that TLS is not reliable too (including the JS code ensuring “security”).

  • When it reaches the server, the server hashes it again (with the same method, or a different one), and stores that instead of the plaintext password

First, you quote someone claiming “the cost of resource-intensive password hashing can be shifted from the server to the client”, that same person suggests actually hashing on the server too, then you suggest the same. Strange logic.

  • The server never ever gets the plaintext password, because it starts off with a hash anyway

Are you trying to hide your credentials from the server?

  • If the server is breached for whatever reason (physical seizure, remote exploit, curious/bored sysadmin, they sold the hardware and “forgot to wipe the drives”, who knows…), then all they will see is the double-hashed values

If anyone installing that server was “clever” enough not to encrypt the drive, then an attacker with physical/file-level access gets all the DB data. You can re-hash the password 1000 times but it won’t protect the actually important information.

Those are all valid points. What would you suggest to rectify/mitigate them?

Do what the docs say - distrust the infrastructure. Allowing the infrastructure (Cloudflare) to generate and know your private key is giving it complete trust - just the opposite of distrusting and securing the end points.

1 Like

I kind of did, actually. You just weren’t happy with the answers…

Does that actually matter in this case?

If the server gets a message it doesn’t understand, assuming there are no parsing errors, it will discard it, which was my initial point.

Not true. This is only the default setting in most browsers, but can be changed or screened.

Um…yes…getting a server to hash passwords of thousands/millions of simultaneous login requests per second (including bots/spam/DDoS) has a resource cost…doesn’t it?

I would say it does :confused:

Here, I’ll show you an example. I’ve simplified it to the SHA-1 algorithm (which you should never use) to make it easy to understand, regardless of the level of understanding of whoever reads this (other browsers of this forum, etc.):

Stage Description Resulting String
1 User enters plaintext password in web browser Password123
2 Client-side code hashes password, before sending it to server, thus ensuring the plaintext password never leaves the client machine b2e98ad6f6eb8508dd6a14cfa704bad7f05f6fb1
3 Server receives string, add its own salt to the end b2e98ad6f6eb8508dd6a14cfa704bad7f05f6fb1SALT
4 Server hashes the new concatenated string a second time, and stores it 9f85383a5f90434a81df38d38bf1591cfcb22efa

The final string 9f85383a5f90434a81df38d38bf1591cfcb22efa is what the server will use to verify login requests.

YES!

Or at least make it a difficult to extract information from any party involved in the transaction, and by the time they figure everything out, those credentials would have been changed.

Zero-knowledge proofs would also be effective, but that’s another topic.


Ok, so we’ve established that you’re happy with a POST request containing a plaintext password for login. Done.

2 Likes

Could someone who isn’t scared of JS be so kind as to post me the
contents of Sign in to GitHub · GitHub
Thanks in advance

I never presume to speak for the Qubes team.
When I comment in the Forum I speak for myself.

1 Like

How exactly are people who use this instance going to contribute to
Qubes? If they post a PR here, will that be mirrored to a PR on GitHub?
Or have I, (as usual), missed the point?

I never presume to speak for the Qubes team.
When I comment in the Forum I speak for myself.

1 Like

I’d like to repeat my previous comment - if you dont want to use the web
interface to GitHub (and that seems to be what this thread is now
about), then you can interact with GitHub using git and gh.

Again, if anyone wants to open an account but is unwilling to do
this because it requires JS, then I’m happy to do this via Tor on your behalf.

Or I’m happy to proxy your PR to GitHub - PM me.

Or you can post PRs and code to qubes-devel

So many ways in which you can contribute.

I never presume to speak for the Qubes team.
When I comment in the Forum I speak for myself.

2 Likes

That’s what I had in mind. A place where anyone could interact with the GitHub via proxy (within reason, of course).

I fail to recall a single time when you have ever missed the point. @unman, you’re pretty on point :slight_smile:


I was just trying to help solve an issue. It’s what I do…

Absolutely.

2 Likes

@unman:

EDIT: I know that @unman interacts via email, and might not get updated when posts are edited, so moving it to a separate post.

1 Like

@unman

github.html.gz (39.1 KB)

1 Like

What you have at the end of stage 2 there is, to all intents and purposes that I can see, the actual plaintext password. i.e. any client that knows the string b2e98ad6f6eb8508dd6a14cfa704bad7f05f6fb1 will be authenticated by the server and they don’t need to know the “original password”. In particular, it adds nothing against in-transit attackers (which are probably towards the bottom of your list of worries anyway once you’re using TLS). Salting with a changing salt (timestamp/nonce) can add something there, but the server can only calculate those values independently if it has the original password.

With password authentication, I would think of it as a shared secret model, and assume you need to trust the server or some subset of its processes. On-server hashing/encryption for permanent storage still protects against some risks, but the authentication process is going to see the bare secret.

2 Likes

I kind of did, actually. You just weren’t happy with the answers…

Actually, you did not. I just had to “fill in the gaps”. :slight_smile:

Does that actually matter in this case?

Does it actually matter if a remote machine sends you code which your machine runs automatically? Good question. What do you think?

Not true. This is only the default setting in most browsers, but can be changed or screened.

How exactly is it “not true”? How many people verify each line of JS code before letting the browser run it (and do it on each HTTP request)? Also how exactly would anyone screen long obfuscated JS (which doesn’t even qualify as open-source)?

Um…yes…getting a server to hash passwords of thousands/millions of simultaneous login requests per second (including bots/spam/DDoS) has a resource cost…doesn’t it?

I would say it does :confused:

Then why are you suggesting it alongside client-side hashing? Why do you even quote a comment which has nothing to do with the actual answers, none of which recommends client-side hashing?

Here, I’ll show you an example.
[…]
The final string 9f85383a5f90434a81df38d38bf1591cfcb22efa is what the server will use to verify login requests.

And how exactly does this theater do anything meaningful in case of:

(A) compromised HTTPS, when an attacker can simply:

  • manipulate data in transit and send malicious JS/HTML; or
  • get the hash (which becomes the actual password) and reuse it;
    (B) compromised server, when the attacker can get anything from the DB (i.e. passwords don’t protect anything any more)?

YES!

Marvelous. So, you are hiding your “secret” from the entity which has direct and full access to your actual account data, protected by that “secret”.

Ok, so we’ve established that you’re happy with a POST request containing a plaintext password for login.

So is Credit Suisse (example excerpts from POST payload with username “aaaa” and password “bbbb”):

SCC_X_TOKEN=[...]&showregistrationstep3=false&registrationflow=false&urlHashParam=&userid=aaaa&password=bbbb&[...]

So is J.P.Morgan:

auth_siteId=[...]&auth_contextId=login&auth_userId=aaaa&auth_passwd=bbbb&[...]

and a million others.

1 Like