Hacker News new | more | comments | ask | show | jobs | submit login
RunJS (lukehaas.me)
228 points by tnorthcutt 42 days ago | hide | past | web | favorite | 84 comments

The third demo screenshot [1], which contains a toy implementation of AES in CBC mode, is a great example of why cryptography is hard to get right. Implementation is best left to cryptographers.

AES-CBC requires a random IV to be used as a nonce on a per-message basis, otherwise the entire scheme breaks. The toy example given on this website uses the deprecated Node.js createCipher [2] API which does not take such an IV. In fact, the docs and runtime even warn that using CBC mode with the createCipher API is dangerous!

As the code is currently written, an attacker observing multiple encrypted messages under the same key could probably decrypt all messages!

[1] https://projects.lukehaas.me/runjs/images/runjs3.png

[2] https://nodejs.org/api/crypto.html#crypto_crypto_createciphe...

> Implementation is best left to cryptographers.

You suggest we hire a cryptographer every time we need something secured?

I mean, come on, this is ridiculous. The code quoted does not implement encryption, it invokes encryption. The AES algorithm being invoked, I expect, was written by proper cryptographers.

The reason this code is insecure is that the API is a piece of shit.

Most standard crypto modules have calls of the form

    encrypt(algorithmName, arg, arg)
Depending on the algorithm chosen totally different parameters need to be passed or else. Or else what? Or else the function works perfectly well, produces an encrypted byte array, but with totally broken security. The programmer will be none the wiser except if they were lucky enough to post the code somewhere on HN and someone writes a condescending comment.

This is shit design and we can blame the cryptographers. It doesn't have to be this way.

Some languages and libraries get it right, here and there. Eg PHP doesn't just expose a way to call bcrypt, but also has two functions password_hash and password_hash_verify. These implement all the best practices, with seeds, the right algorithm parameters, keeping the ability to rehash in the future, etc.

We need similar APIs for symmetric and asymmetric encryption, for common use cases, or this madness is simply going to continue. Cryptographers, please get your act together. Job safety is nice, but a secure internet is nicer. Please make it easy for morons like me to use crypto right.

I mean, I don't even know what the different considerations are so I can't design these functions right, so please consider the spirit of the following proposal and not the details.

What about a function like encrypt_symmetric_for_single_user(payload, userid, key) which takes care of picking the right algorithm, doing the right dance with keys and nonces and whatnot? Or maybe functions need to include naming like encrypt_for_sending_once and encrypt_for_storing_long? My understanding is that you want different crypto in such cases, right? I'm sure better cryptographers than me can immediately see what I'm doing wrong here, but you catch the gist right? Why can't this be made easier? Why do we at the same time, collectively, shame everyone who gets security wrong and make it so unnecessarily hard for people to get right?

NaCL: https://nacl.cr.yp.to

Is a crypto library designed to do exactly this, have a sensible API that does not expose any internal details for misuse, and generally gives you only one way to do things based on best practice algorithms.

It's got some big names behind it, and has probably quite mature since it's been going for several years.

There is also a popular fork, libsodium: https://libsodium.gitbook.io/doc/, which I think is more portable.

I like the idea of NaCl, but IMO it doesn't go far enough. For a concrete example, it lacks PHP's password_hash and password_hash_verify functions, essentially being one level of abstraction lower.

Also the documentation does not mention much in the way of how to _use_ the library. Do I send the nonce along with the ciphertext? Do I need to authenticate the nonce as well, then? To me it looks like NaCl and libsodium are still very much written by and for cryptographers.

Eg, many functions take nonces. Correct me if I'm wrong, but why can't they generate those nonces for me? Return a struct with the ciphertext and the nonce? Or have a make_nonce function generate a Nonce struct and only accepting that instead of a string?

I recognize that some of crypto, especially much other stuff than password hashing, is just intrinsically hard. But the APIs should expose only this intrinsic hardness and design the rest simply so you can't use it wrong. It's the exact same critique as a database client library that makes passing data separately harder than putting them right inside the query string (eg PHP's original mysql_query). Those are crap APIs and crypto APIs that let me screw up without even so much as a warning are also crap APIs.

Finally, to get into some classic HN style bikeshedding: 'NaCl (pronounced "salt")', really? So the idea is that when Bob recommends that Alice "just use salt", she understands that Bob means NaCl and not "just use a salt", the much more probable and totally wrong interpretation. Nonsense like this does not give me much faith that a library is designed for real world use by normal engineers.

Update: wow, the libsodium docs got a lot better since last time I looked at it. Eg [0] is clearly written for normal developers and not for crypto people. Cool!

I'd still love a library at a higher level of abstraction like I described above, but nevertheless I think this is cool.

[0] https://download.libsodium.org/doc/secret-key_cryptography/a...

Tangentially relevant but here's a great example of important the AES mode can be:


The `createCipher` API derives an IV from the passphrase so basically it uses a static IV for each passphrase.

If you used it and need to switch to the new API but be able to decrypt old stuff, here's some code to get the IV that the deprecated API actually derives, so you can use it with the new API: https://gist.github.com/bnoordhuis/2de2766d3d3a47ebe41aaaec7...

I totally understand why you're saying what you are, you want folks to be safe... but I think this approach from cyptographers hurts the rest of us, in that most of us will at some point say, as a result of comments like this, "I'm not a cryptographer, I cannot do this correctly... so fuck trying." I think critiquing this crypto used would be more relevant if he was implementing his own and not using using an outdated library.

Instead of linking to proof about how right you are, since you obviously are, perhaps next time you could link to resources for us plebs to stay up-to-date. How do you keep tabs on "all the things" like this?

/shrug just my two cents.

Cryptography is like civil engineering or surgery. If you're going to do it in production, you need to do it right.

I think it's akin to a family physician saying, "this is best left to the surgeons."

Don't be fooled that just because you can write code, you can do crypto. But also, you can learn and you can also completely mess around in a safe, non-production environment.

Maybe my analogy is a bit weak.

I think your analogy is pretty spot on. Cryptography is an additional skill on top of general programming, and it's a difficult one to master. And if you haven't mastered it, then you shouldn't be trying to do it in important situations (assuming there is an alternative).

I disagree, cryptography is like any programming; make sure it’s correct with tests, peer review and validation and check the warnings (this warning should be an error). The fact that a small example gets this badly wrong and the API allows this is probably down to the ecosystem, not down to only cryptographers being “allowed” to used crypto. The surgery idea is wrong; surgery is the implementation of the encryption which no one is advocating - this is more like a pharmacist giving you the wrong pills and you not reading the instructions/warnings before taking them.

I think explaining why the crypto usage is wrong is useful, where a straight-up admonishment that someone is doing it wrong isn't.

The principle here is explained, at least partially: if you don't use a random IV for every message, you're not secure. So if the API you're using doesn't let you specify the IV, or doesn't default to a random IV that leaves you with undecipherable blocks if you don't fetch its assigned value, you know it's wrong. It's good info.

> most of us will at some point say, as a result of comments like this, "I'm not a cryptographer, I cannot do this correctly... so fuck trying."

I'd argue that in most cases not using crypto is better than using subtly broken crypto. At least users aren't deluded into thinking it's secure, and can take that into consideration when using (or not using) the system.

> "I'm not a cryptographer, I cannot do this correctly... so fuck trying."

Whoever says this, whoever doesn't put in the hard yards to actually get good at cryptography, who is content with hugely flawed crypto — well, they shouldn't be in crypto in the first place.

And those unable to take constructive criticism, I don't know if they should be in real life.

This kind of as-you-type evaluator is extremely valuable to me. I've written a few tools to support this in emacs, and I use the JS one all the time.[0]

I also wrote one for Graphviz (which outputs to an SVG buffer), and sometimes I'll put the output from the JS playground in `play-graphviz` mode so I can see real-time graph output from JS (by writing code to print dot graphs). ATM I don't know any other tools that can do that sort of thing, let alone compose independent ones to that end. Long live Emacs!

[0] https://bitbucket.org/gavinpc/play-modes/src/default/js-play... (There is an odd bug in OSX where the first character of the input is eaten, so I always begin these "playgrounds" with "/// playing with <whatever>". There are some other oddities which I should document.)

Why did you decide to make this as a standalone application instead of making it as a plugin to an existing editor? Seems like a lot of work for what seems to be a custom repl.

Guessing it’s an Electron app, in which case it’s more along the lines of a desktop-packaged website.

Quokka.js works nicely in vscode which means I'm only running one electron app not two (not that I care about electron memory usage, as long as the application feels fast I don't mind if it's 15Mb of memory or 150Mb, I have 32768 in my laptops and 65536 in my desktops).

8192 MiB, or even 4096 MiB in a laptop is still common nowadays, and single Electron apps using 256 MiB is not unusual.

Quokka works in the IntelliJ family of IDEs as well.

Why's it Mac-only if it's Electron?

Even if it's Electron you still need to package a binary for each platform...

Does node not support cross compiling??

It does, but it takes effort and I believe that Windows compiling is hard work on Mac.

Depends on what you use to package. With electron packager (https://github.com/electron-userland/electron-packager) it's really easy and fast to package on a Mac for Windows and Linux. The only real pain for multi-platform packaging is that you need to have a certificate both for Mac and Windows.

It's not hard at all to compile and build a package for Windows on Mac.

On the other hand, want to add an icon to your Windows app from a Mac? Jump down the rabbit hole of installing Wine and other dependencies and watch it spend minutes trying to invoke rc-edit.exe on Mac to make it work.

That's awesome. I have always wanted something like this. I was even looking for some sublime text plugins that evaluate code on the go, but was out of luck.

Some use cases :

- Coding interview

- Stack Overflow answers playground

- Instead of "node -pe ..."

Light Table comes to mind: http://lighttable.com/

There are many vscode plugins that will evaluate code and display the results inline (the build in debugger does this too if you pause execution). You can find them pretty easily in the visual studio marketplace.

Which one is your personal favorite?

I generally use jsfiddle for these kind of things, but AFAIK it doesn't do es6 or Typescript, so RunJs looks like it's worth a try.

Ah, didn't notice it was Mac only, which is a deal-breaker for me. Also kind of odd for an Electron app.

i like this idea so much. i wish the author the best of luck, i will be following development. some basic features are missing: autocompletion, in-editor help and documentation, and my own nitpicking favorite: font size!! -- i know, i know, there is that zoom in thing that seems to work sometimes...

i grew up with environments like QBasic and TurboPascal. they had everything you needed to learn and master specific languages? all in one package.

JavaScript is so lucky to have such easy integration with the electron stack. and with all the bad rap electron apps have been getting, this is just 160MB unzipped. the closest we have for Python is the mu editor. that editor is half a Gb unzipped!!

also, could it be that adding more features and library would make the size go up? who knows? anyways, looks good.

Being an electron app, Im surprised it only consumed 150 mb of ram and spawned 4 processes just by opening it.

Is it a good number for Electron apps? Is it ok nowadays? 150MB seems too much for me. I also thought that by using Electron an app would be readily portable but I could only find Mac binaries.

150MB is really good for an Electron app

Oh my God I thought he was kidding. How did it get to this? And how do we solve this?...

Electron is one of the reasons apps like this even gets made in the first place, other options are often not worth the time of development.

A solution to reduce the size could be to ship the Electron runtime similar to .NET, etc.

However, PWA's are probably going to be the best bet going forward.

Could something like Android webview work? The webview doesn't force each app to include a whole browser. So, maybe single instance of electron runtime with multiple thin apps with "electron-webviews".

Don't use Electron apps?

How did it get go this?

Well that's what you get when the "solution" is to embed a webserver, a browser, a native executable to show that browser, and the server runs Node...

The solution is simple, stop shoving square pegs in round holes, and learn an appropriate language rather than shoehorn JS everywhere.

> learn an appropriate language rather than shoehorn JS everywhere.

Being that this app's sole purpose is to evaluate JS, this may be a situation where JS isn't being shoehorned

By the looks of it, only the console (Or equivalent) is used for output, so bundling an entire browser seems way overkill for the output.

There's plenty of ide-libraries in other languages to replace the one used by runjs.

You'd still have to bundle a JS engine. Presumably you could build a traditional UI app and include V8, but I still think this isn't a bad use case for Electron (but I agree there are many apps where it isn't the best choice)

I'd imagine that the browser is the resource-heavy part of the application, Nodejs doesn't use hundreds of mb's of RAM in my experience, at least not while doing very little background work.

To me it would make sense to build a real desktop application and bundle whatever JS engine you want to use, pipe and process the output as any other application.

You'd end up with a much smaller application (Download size), more resource-efficient, and less reliance on things like the bundled browser.

> You'd end up with a much smaller application (Download size), more resource-efficient, and less reliance on things like the bundled browser.

None of these things I care about. I care about whether or not it serves a purpose to me. If it does, I'll use it. If it doesn't, I won't. You might have other priorities and that's your prerogative.

yep - that's pretty minimal - about what I get when I'm just starting off with a skeletal electron app.

for refernce, on win 10: whatsapp - 200+mb and 4 processes. slack - 325mb and 5 processes.

Also consider flems.io , a similar evaluate-as-you-type but for JS, HTML, and CSS.

Learning some JS to help out on a project. Having a good time playing around with this as I read through a JS intro book. Nice and easy to check things out as I work my way through code examples throughout book.

"RunJS will auto-evaluate your code as you type"

Interesting. Is it in some kind of sandbox, or can I accidentally remove files, etc?

Edit: Oh, it's an ios app?

macOS app

Well that certainly makes it worthless to 90% here then.

More like to 60% here. A shitload of devs use OS X -- and the platform has come quite high on the kind of HN crowds, more so than on the generic public (as is evident by the speakers and even attendants on most dev conferences).

In my specific case (maybe my case is the majority, maybe not), I run macOS only because I want a no-nonsense laptop that just works. For the combination of good hardware, good display and good build quality, I found the Macbook Pro (2015ish) to be the best bet at the time, and it has served me well thus far.

Prior to that I was using a very cheap but sturdy Samsung with Linux on it.

On the Desktop I run Linux and Windows (only for Steam every now and then).

It's not a MacOS app, it's an Electron app (So, just a web browser bundled to look like an app)

Compiled and available solely for MacOS, though. Odd.

It is odd.

This could be useful! I hate typing in some random chrome window for just testing out something super simple.

It is however surprisingly slow to execute the code on my machine. At first I thought it was the auto run delay, but even when running it manually it takes ≈ 0.9 seconds. Not really a problem, but I expected it to be quicker.

Let me recommend Observable notebooks, https://beta.observablehq.com

I used to use this: https://github.com/princejwesley/Mancy

Sadly, it hasn't been updated in years.

It's all fun and games until you write out a destructive line of code.

I don't know this, but Chrome DevTools' eager evaluation uses a pretty smart V8 internal tooling to figure out if your statement has a side effect, and only evaluates it if it does not.


Thank you, this seems very useful and much nicer than doing a jsfiddle as you can work locally. There's nothing wrong with reposting good work as I would have missed it otherwise. Bravo.

Pretty cool. Only issue is not being able to exit from an infinite loop.

let x = 2; for (let y=0; y < 10; x++){ console.log(x) } x

The next feature should be detecting whether or not there is an infinite loop and warn you before running it.. /s

I know this is a joke about the halting problem, but some kinds of infinite loop can be detected.

Why is Nan === NaN; false considered a quirk? It works like so in every language I have ever used.

So LINQpad but:

- for Javascript

- only for Mac

- evaluates JS as you type


It reminds me more of Light Table than LINQpad or RoslynPad.

It's pinned in my dock! <3

I was interested to try it. Clicked into the code 'Uhh.. this is ... an image?' Saw the 'DOWNLOAD RUNJS' button. Smiled. 'Download? That reminds me of the 80s where we traded software on floppy disks'. And I was reminded of...


Thanks for the nostalgica.

If you ever decide to make it available in the browser, I will try it.

I had the opposite reaction - mine was 'thank god this is not yet another thing I have to be online for'

If you would like a solution that works in the browser, you can try our project, https://runkit.com. It gives you access to real node (every version), and already had every version of every package of npm pre-installed.

coldtea 41 days ago [flagged]

>I was interested to try it. Clicked into the code 'Uhh.. this is ... an image?' Saw the 'DOWNLOAD RUNJS' button. Smiled. 'Download? That reminds me of the 80s where we traded software on floppy disks'.

This reminds me of before 2010, when we though web apps will eat the world.

Have you been living under a rock? Mobile apps have taken over since where the action is (on mobile), and even on the desktop downloaded apps are doing just fine (even if some use web technologies like Electron).


> So what's the point of providing these links? Are you gatekeeping people reposting things?

Why are you being so hostile?

I didn't get hostility from the comment. I agree, only reason to link to previous submissions is when there was discussion.

>I didn't get hostility from the comment.

Jumping down my throat due to my otherwise benign comment is being hostile. Perhaps a conversation may take place next time; could even instruct me -- as you had here -- that "only reason to link to previous submissions is when there was discussion." Instead, asks leading questions, and some indirect accusation of gatekeeping. That's pretty far to take things based off a four word comment containing two URLs; you had to assume a lot in order to get that bent out of shape.

Your account is 6 years old; I assumed you're familiar with how people link previous discussions on here and didn't need to be "instruct[ed]."

As far as I could tell the only point of your comment is "repost alert!" which is why I asked. Since all you've done is take offense and not provide any explanation I take it I was correct.

dont put links from last time..

When did you stop beating your wife?

Ah, JavaScript, only for Mac.

What a weird world this is.


Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact