Hacker Read top | best | new | newcomments | leaders | about | bookmarklet login
A Javascript journey with only six characters (jazcash.com) similar stories update story
567 points by Jazcash | karma 278 | avg karma 18.53 2016-10-08 05:01:13 | hide | past | favorite | 123 comments



view as:


I created an account just to thank you for that post, so funny :)

I'm getting a browser security warning on the url on Android.

this is insane. someone should create a js obfuscator that converts human readable code to this.

It is linked at the end of the article:

http://www.jsfuck.com/


some how the link to http://aem1k.com/aurebesh.js/ is missing, where he takes this one step further.

Oh dear...

With some code you don't need to run it though an obfuscator for it to be obfuscated

this would obviously be a fun thing to do, but I wonder how much larger the code will get via this means of obfuscating.

Maybe space isn't a concern in your use case though...


I imagine it could be largely mitigated by compression

I have a "compression" feature for my jsfuck fork: http://centime.org/jsfsck/

only worth it for long enough code, but then the browser is having a lot of trouble parsing the obfuscated version...

Still: "The js code of this page has been encoded (see source). Compression reduced it from 288k to 37k characters."


The title is incorrect; you need "!" and the only reason why I clicked on the article was that doing it without "!" would be a BIG deal. The title of the original article is "A Javascript journey with only six characters" and the topic has been posted/reposted and explained more times than I can count on HN

Oh sorry, how could I miss that :( Fixed it now

This is an extreme demonstration of the validity of a delightfully snarky blog post by Robert Harper on how dynamic typing is actually static typing using a unitype:

https://existentialtype.wordpress.com/2011/03/19/dynamic-lan...

A string is a Boolean is a number is a function, and braindead conversions can happen without anyone noticing. How does one keep their sanity using a language like that?


With something like flowtype.org.

Good answer. Of course, supplementing static typing after the fact only goes to show that it should have been built into the language to begin with.

Keep it straight in your head, and use strict comparison.

Hey, at least when JS implicitly converts your types, it actually does type conversion, rather than merely casting them, so you often get what you want (looking at you, C).


As for C, I have to contradict you. Implicit (numeric) type conversions do actual conversions (like char to int, or int to double; even pathological cases like pointer to what-counts-as-Boolean-in-C). The casts you are talking about must be explicit, and thereby are squarely the programmer's responsibility.

Of course, a language that forces all conversions to be explicit is preferable.


I was pretty sure that char to int/int to char in addition was implicit...

Yes, but the char still has to be extended to int. Or the int truncated to char. Except on systems where they happen to be the same size.

EDIT: Supplement: The notion of “type” in C is best translated as “memory layout plan”. Languages of the ML family (including Haskell), e.g., have a notion of “type” closer to mathematical concepts.


What the OP takes to the extreme is a property of weak typing, not dynamic typing.

These properties are separate issues. A language is either statically typed or dynamically typed, and it is also either strongly typed or weakly typed.

In a statically typed language, types are attached to variables. In a dynamically typed language, types are attached to values. Do note that many languages don't fit 100% into either category. (Note that the blog post you linked to calls types attached to values classes, but that distinction often isn't made so clearly.)

A weakly typed language performs implicit type conversions as it deems necessary, while a strongly typed language does no implicit type conversions. Most languages don't fit 100% into either category. Usually languages that are considered to be strongly typed still allow you to add integers to floating point numbers, for example.

It is possible for a dynamically typed language to be so strongly typed that it won't do any implicit type conversion, ever. Such a language would not allow you to, say, add an integer and a floating point number without explicitly converting one to the other.

It is also possible for a statically typed language to be so weakly typed that it implicitly converts types everywhere. Such a language might do the exact same things the OP uses, like converting a function to a string of its source code when adding it to a string.


Ah, this was extremely well explained, thank you; I've encountered the strong / static (and weak / dynamic) dichotomy before but I didn't grok the difference until now.

> In a statically typed language, types are attached to variables.

More precisely, expressions may be typed. Of course, free variables are one particular of expression.

> In a dynamically typed language, types are attached to values.

More precisely, tags are attached to objects. An object is a “physical” entity that exists in space (computer memory) and time (from its construction to its destruction or garbage collection). A value is an abstract and atemporal entity that only exists in the language's semantics.

> Such a language would not allow you to, say, add an integer and a floating point number without explicitly converting one to the other.

But it does allow you to add integers and floating points! The result just happens to be an exception, which is a very well defined operation in the semantics of most high-level languages.

If it weren't allowed, it simply wouldn't happen.


In a dynamic language, you have to wait until runtime to decide whether an operation is valid or not. Only then can you check an object's tag to see if it proclaims the right type. If it doesn't, non-local exit (of which the exception is the most popular form), is still the best you can do. So, cum grano salis, throwing an exception is a dynamic language's way of disallowing invalid operations.

This isn't true. Throwing an exception is a perfectly valid operation. Of course, it is not the operation you want, but that's a-whole-nother matter.

I didn't say throwing an exception is an invalid operation.

How does your dynamic language tell its user an operation is invalid, based on argument type?


> How does your dynamic language tell its user an operation is invalid, based on argument type?

It doesn't! That's exactly the point. If something is invalid, then it can't happen. At all.


If only. What language are you talking about, exactly? This unicorn I have to see.

Any memory-safe language? Say, Python. `[] / []` is a perfectly valid operation: its result is a raised exception misleadingly called `TypeError`. OTOH, in most typed languages, this is a genuinely invalid operation, and it can't happen at all.

Reminds me a bit of the quest for alphanumeric shell code.

I'm a fan of Javascript. It has proper lambdas, true lexical scope, will soon have TCO, and is a really flexable language.

But it's not without its warts, and this is one of the worst. Although it's sometimes fun to mess with, nonetheless.

To see this taken to one of its logical extremes, check out If Hemmingway Wrote Javascript's entry for Douglas Adams:

  // Here I am, brain the size of a planet, and they ask me to write JavaScript...
  function kevinTheNumberMentioner(_){
    l=[]
    /* mostly harmless --> */ with(l) {
 
      // sorry about all this, my babel fish has a headache today...
      for (ll=!+[]+!![];ll<_+(+!![]);ll++) {
        lll=+!![];
        while(ll%++lll);
        // I've got this terrible pain in all the semicolons down my right hand side
        (ll==lll)&&push(ll);
      }
      forEach(alert);
    }
 
    // you're really not going to like this...
    return [!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]];
  }

That reads like a close cousin of brainfuck...

exactly

For those of you too lazy to open up a Javascript console, it's a function that returns "42".

It also alerts all the primes between 0 and its arg.

For those not in the know or too lazy to Google, that's "the answer to life the universe and everything"

Or too lazy to work it out in your head. Jeez.

Lexical scope with async closures makes it very easy to write async code for example events in a gui or handling multiple clients in a server. Its a big deal.

I knew about these languages but I've never understood how they were made. This is a fun, fantastic article! These articles make me excited about technology. Even bad ones.

One more reason for the world to hate JavaScript ? :(

It's too bad that people were willing to ostracize Brendan Eich for not being a cookie-cutter silly-valley progressive.

Oculus is facing that now. It's the new mccarthyism.


It's hardly the new McCarthyism when there's no government force that leads the charge against private citizens, driving them to be unable to find any work in their field in the US.

The public deciding that it doesn't want to support someone is an entirely different phenomenon. The public can still be wrong, of course, but there's no need to conflate the two situations.


They're both the phenomenon of policing thought and coercing others to publicly profess, or at least acquiesce to, only blessed opinions. It hardly matters, to this point, whether the behavior is centralized or emergent.

Well, that's hardly true. I thought we'd established that JS in inferior to Lisp.

;-)


You forgot this: (

That's only funny once.

Then it gets frustrating;

DAMMIT where the heck is it!!!


That, OTOH, might be funny for a second time. Maybe.

For what it's worth, Brendan Eich is a joke for technical reasons as well, like creating JavaScript.

That's un-called for.

I don't like him because he's fat.

http://a.abcnews.com/images/Social_Climber/GTY_brendon_eich_...

No other reason.

I just can't support the immoral glutton lifestyle.


And how many users does your programming language have?

We would be better off if JavaScript didn't exist, so by that rationale I've contributed more than him by not creating a language.

Well, it's not like he wanted to do it.

You would be better off. I love JavaScript, it's my favorite language (I like things that are accessible to everyone), so I would be worse off.

Well that escalated quickly.

> ostracize

Brendan has his own startup in SV and appears in JS community podcasts, conferences, and meetups. The community is always talking to him on Twitter in a positive way. He may have had to leave Mozilla, but he's anything but ostracized.


It's too bad that people are willing to use their money and influence to negatively affect specific groups of people. Both Eich and Luckey made personal choices that negatively affected users of their products. As a response, these users, and people who support them, have decided to reject them.

No, it's not too bad that assholes are called out.

This feels like basically the reverse of the ad hominem, where if you agree with the things someone is saying in a particular context, you also have to praise them as a person. And it's a fallacy for the same reason the ad hominem is a fallacy. I can respect Brendan Eich's technical views without having to respect his political / social ones, and I can believe that he's amazingly qualified to be CTO of Mozilla, a technical role, and yet amazingly unsuited to be CEO, a political/social role. And this isn't just me - none of the controversy started until he moved from CTO to CEO.

If we can't do that, then we ostracize people who aren't a cookie-cutter $political_view.


oh man totally. neither brendan eich nor palmer luckey have gotten any work ever since they were blackballed by silicon valley.

oh wait. they weren't was blackballed. and one has his own startup, the other is basically set for life.

oh wait. has either one of them appeared in from the a senate committee to defend themselves for false accusations of subverting the u.s. gov, or committing treason? without any evidence?


We detached this subthread from https://news.ycombinator.com/item?id=12666782 and marked it off-topic.

This doesn't make me want to use JS. The power of JS is in two things, it's in every major browser and it doesn't completely suck. JS syntax kind of sucks. The power in JS is that it's dynamic and lets you send functions around, but defining functions is much uglier than defining a lambda in Ruby:

-> {anything goes here}

or

->(a,b,c) {anything goes here}

The problem with Ruby is that you then have to .() the lambda vs. (), so that is more verbose than just calling the function.

If browsers were to embrace a language that was more Ruby-like and less clunky than JS, I'm sure I'd use it more.


ES6 lets you define functions like a => a * 2

Or (a, b, c) => a * b ^ c


That's succinct, but less clear than the Ruby version, imo, as you don't have any scope indicators required for the function body.

JS:

  let f = (a,b,c) => a * b ^ c;
  f(2,3,4);
vs. Ruby:

  f = ->(a,b,c) { a * b ^ c }
  f.(2,3,4)
Ruby's shorter and clearer. But, when you use the Ruby lambda more than once in the code, you lose the brevity advantage, because of the "extra" dot. But, in Ruby I use methods more than lambdas, which would be:

  def f(a,b,c) { a * b ^ c }
  f(2,3,4)

None is preventing you from writing let f = (a,b,c) => {a * b ^ c}; in JS

when you include curly braces in arrow functions you lose the implicit return, so this function would return undefined

very true :)

You can get the implicit return if you use parentheses instead:

f = (a,b,c) => (a * b ^ c)


the ruby versions isnt shorter though; you just included things you dont need: semi colons and 'let'

> Ruby's shorter and clearer.

I would say the different is negligible here and claiming one is more clear than the other is purely preferential. Coming from a JS background the JS is more clear but not substantially enough for me to claim it is outright more clear a language syntax. Someone coming from a ruby background may argue the other direction.

Some languages are quite different but you are splitting hairs here and trying to be conclusive about it.


Ruby suffers from a confusing set of overlapping features in Procs, Blocks and Lambdas. JavaScript's function passing is a lot less opaque.

The article does not explain how it gets the {}, which is used to get the Object constructor string. Other than that it's very clear.

It does, see the "fill" step: «So now we have acquired the following extra characters: c,o,v,(,),{,[,],}, .».

Those characters are only inside a string, not as executable code.

But you can execute strings...as it says in the article.

Yes, but not at that point in the article yet...

Good catch. It seems that the "Object" string doesn't provide any crucial characters for further steps; in this case the literal curly brackets aren't needed.

You're right. It's possible to use it later on but I've removed it as it doesn't make sense being at that point in the post chronologically. Thanks!

Why do I feel like I have read this article a few years ago? I remember it, but it has 2016...

Because you did. I came to the comments wondering if this was a shameless ripoff of the original or a re-post from the same author.

If it's similar to another article, I'd love to see it. I wrote this over the last two days using only the sources noted at the bottom of the post.


Those links are to generators, not easy-to-read long-form explanations.

I think the problem is your post reads like it's a discovery of your own, jsfuck and previous artwork are only hinted at the end.

The style makes it easier to see how the approach works, and wouldn't say it implies the OP came up with the technique.

It seems that explanatory articles of this sort often use this style, as it is a great way to get the idea across.


Because this technique was used to bypass EBay's JS blocker a while back.

Interesting, any chance you have a link to a writeup of that?


Thanks!

The fact that eBay can't or won't fix the vulnerability this enables is disgusting.

Does anyone know a good sandboxing technology to execute user written javascript in a safe way? (like, on other user machines or on the server)? I have some ideas like "learn programming" that would benefit from this immensely.

https://developers.google.com/caja/

Used it a few years ago. It was a little finnicky to get working right but I was impressed at the time. No idea where the project is at nowadays.


i saw caja, but it looks really complex, was hoping for something better these days :(

Note that caja doesn't protect against local denial-of-service attacks: user-written javascript executed with it could allocate tons of memory or run forever (`while(true){}`). This may or may not be a problem depending on your use-case. (If you're using caja for code written by mostly-trusted 3rd parties, or for one user's code only on their own machine, then it's not much of an issue. If you're serving code written by one user to another, then it could be a problem.)

Ha, here's an old thread where I asked the caja developers about that exact scenario: https://groups.google.com/forum/#!topic/google-caja-discuss/...

Some possible mitigations but I don't know if they ever implemented them.


What about Node.js's `vm` module?

thanks, I didn't actually know about that. it looks like a perfect (and simple) solution for running on nodejs. wish there was something like that for browsers too!

edit: i guess there is this: https://github.com/substack/vm-browserify


Note that the vm module doesn't protect against local denial-of-service attacks: user-written javascript executed with it could allocate tons of memory or run forever (despite any configured timeouts: https://github.com/nodejs/node/issues/3020).

The safest way would be to embed an interpreter written in JS and remove any sort of I/O or FFI capability from the interpreter.

Niel Fraser, the guy who created the Blockly block programming toolkit also created a JS Interpreter which allows single stepping of code. https://neil.fraser.name/software/JS-Interpreter/docs.html

I've hacked on this interpreter some, it's pretty nice to read! It implements a very limited subset of JavaScript, something like ES3.

I'd be really interested to hear about other similar implementations of JavaScript in JavaScript. I stopped working on https://github.com/thomasballinger/hotswapping-js-interp#js-... partially because copying the state of the interpreter was relatively slow. I'd be interested in implementations that would handle this better by using a more bytecode-like VM or immutable data structures.


wow! this is really awesome and perfect for my needs. thanks very much :)

Without parenthesis (requires 8 characters though):

http://centime.org/jsfsck/


I don't see the point of a programming language allowing itself braining fucking its users(developer) for serious use

All those idiosyncratic moments were taken into Javascript right from Perl. Perl can do this and much more.

And Perl codebase is huge. Perl is used quite heavily at Amazon, Booking.com and Yahoo, among others.

Say what you want about Perl, but it is fun and hacker-friendly. I enjoyed it for many years.


It's optimizing for writeability rather than readability.

If you don't like JavaScript's type coercion rules, fair enough. But if you're criticizing the fact that you can write JavaScript programs with nothing but punctuation characters, remember that no-one ever does so except as a joke, and that you can do ridiculous stuff in most languages. (Try Googling "obfuscated $YOUR_FAVORITE_LANGUAGE".)

This is quite timely. I was looking at a library the other day which had IIFEs preceded by '+'. I wondered what the purpose was. Now I know!

Wow, JavaScript is also an esoteric Language.

I remember similar strange and interesting stuff in Perl, like the spaceship operator.


So glad I don't write in a "weird and wondeful language that lets us write some crazy code that's still valid"

> Javascript is a weird and wondeful language that lets us write some crazy code

Wondeful! A typo six words in.


Why do you care?

I thought it was an amusing parallel to the title.

I saw a similar video recently called Code Without Keywords which was quite interesting.

https://www.youtube.com/watch?v=LG-ozmTnhdI


I sighed with relief that the characters were not emoji.

neat

Legal | privacy