Curtis Z

22 posts

Automatic Semicolon Insertion Is Evil

Here's an edge case from hell... Imagine your team inherting a cool-looking JavaScript project at work. It's an enormous amount of code, but mostly it's a server-side application. As time goes on, your team is tasked with building on the client code, and you're adding features and fixing bugs as the project develops. Then one day your team decides it's time to minify the client-side JavaScript. "Easy," you think, as you fire up your favorite minifier. Suddenly, an error appears. And another. And another. As you are putting out the fires, it dawns on your team that something was very, very wrong with the code. The original developers chose to rely automatic semicolon insertion in their JavaScript, and minification has just potentially destroyed this project. This is just one example of ASI coming back to bite you in the ass. The same thing will happen to your ASI-filled JavaScript after you put it on CloudFlare (they use an in-house minifier). The potential for disaster is just too great.

There are many posts about the dangers of ASI (importantly, this one by the creator of JavaScript).

Automatic semicolon insertion is not a simple stylistic choice, no matter what anybody says. This is not the same thing as deciding where to put curly braces in your if statements. If you are relying on ASI to complete your expressions and you don't know the precise mechanism used by your JS interpreter for inserting semicolons, you are writing broken code. I am certain anyone who says ASI is worth the trouble has never spent hours debugging script which works until it gets munged in a minifier. I realize it's pretty trendy and cool-looking not to use semicolons, but you are punishing the programmers that come after you. Even if you know the rules by heart, you shouldn't use ASI unless you know with certainty that this script will never be minified in the future. If you are writing JavaScript that anyone else may one day be responsible for, you are punishing other programmers with your code by relying on automatic semicolon insertion. And that doesn't make you cool at all.

SSL-Enabled Content on AWS CloudFront Using a Custom Domain

Amazon Web Services offers CloudFront, and the ability to serve assets across CloudFront via HTTPS. As we move into the near term future of security on the internet, you should be doing HTTPS-enabled devops and development where possible. At least until someone simplifies this awful, complicated mess of protocols and practices: I deal with SSL certificates all the time and I still don't know most of the commands by heart. And everywhere you look online, you'll see tons of evidence that I'm not alone. For example, the entire first page of Google results for generating private keys with openssl will almost ubiquitously create the keys using the -des or -des3 option. Then a paragraph or two later, they go through an entire step describing the process of removing the encryption password on the keys they just generated! If this isn't proof-positive that most people mostly don't know what they're doing, I don't know what is (and we're ignoring of course that this is basically an appeal to popularity by involving the first page of Google search results).

Anyways, I recently moved several of my websites to HTTPS, and therefore wanted to serve my CloudFront assets (jQuery, Bootstrap, Angular, etc) over HTTPS from my own domain (i.e. not using *.cloudfront.net). In order to do this, Amazon requires that you upload your signed certificate to the IAM certificate server. This is the kind of process that can easily consume a couple of hours for no real good reason other than that Amazon's documentation says a whole lot of nothing useful. Seriously, when I see documentation like this, I know the company has gone far too Enterprise for me to ever want to work there. And Amazon's recruiters for some reason just won't leave me alone. Anyways, that's tangential.

What we're trying to accomplish here is pretty simple from an overview perspective: We want to load our CA-signed certificate file to the AWS IAM Certificate server, and then we'll go into CloudFront and assign our HTTPS connections to use that particular certificate. Sounds neat, but worry not, young padawan, it gets convoluted in the implementation.

First, there is no web interface for uploading certificates to the IAM Certificate server. You have no option but to use the aws-cli utility (sudo apt-get install awscli on Ubuntu 14.04-based distros). Get ready for it, the command looks like this: aws iam upload-server-certificate --path /cloudfront/mysuper/ --server-certificate-name MySuperCert --certificate-body file:///home/user/Downloads/mysuper.crt --private-key file://mysuper.key --certificate-chain file://mysuper.chain.pem. It doesn't say in the documentation we're focusing on (though I'm sure somewhere in that ocean of documentation it mentions configuring the utility), but you need to run aws configuration in order to input your IAM User access key and secret. For the purposes of uploading to the IAM Certificate Server, you're also going to want to add the AdministratorAccess User Policy to your user on the AWS Management Console in your browser. Once you're done uploading your certs, it's a good idea to remove this access if you aren't going to be doing this often. So far, we've now had to interact with the web UI and also the CLI to get this job done, and we're not yet finished with the gotchas.

Please take note of the file:// format you MUST specify for each option. You must be in the same directory as the files you're working with if you're not going to specify a full file path instead of a filename. To help you wrap your head around this, I've used both types in the command in the last paragraph. Oh, and Amazon requires your CA chain file to be in a different format than what virtually everyone else uses. Most CA chain files come with the root CA certificate at the top, then your intermediate CA signatory certificates, and then finally your domain's certificate. This is sane and ubiquitous. Amazon wants "a subset" of this collection (i.e. just intermediate and root CA certs), in reverse order. So for example, if you're using Comodo SSL certs, you're going to cat COMODORSADomainValidationSecureServerCA.crt > mysuper.chain.pem and then cat COMODORSAAddTrustCA.crt >> mysuper.chain.pem and finally cat AddTrustExternalCARoot.crt >> mysuper.chain.pem. You're going to be unable to use the certificate unless you specify a --path that starts with /cloudfront/name/ where name is a descriptive name for your user (and don't forget the trailing slash).

And now finally you're ready to run the command in the paragraph above. God and Amazon willing, you'll get a success message in the form of a JSON object called "ServerCertificateMetadata" with several properties, including the ARN of your uploaded cert.

Now all you need to serve your S3/CloudFront assets over HTTPS from your own domain is to head to your CloudFront distributions interface. Then select the distribution which you want to use your newly-uploaded certificate, click Edit on the settings page, and where it says SSL Certificate you should now have the option to select Custom SSL Certificate (stored in AWS IAM) and use the dropdown to select your certificate by name. Make sure you select Only Clients that Support Server Name Indication (SNI) in the section labeled Custom SSL Client Support below, unless you know you need to support non-SNI-capable clients (and have ample coin to spend on the setup, which can get expensive due to dedicated IPs).

Finally, if you're an architect at Amazon, let me plead with you to reduce the drinking-from-a-firehose feel of the documentation for AWS, and to reevaluate any action that requires both the web UI of the Management Console in addition to the AWS CLI utility. For me, when software has a brittle configuration process, I get the impression that it's not very good software. I love AWS and I've been using it for years (and will continue to do so). But there is so much about it that could be improved.

Stop saying "soft tabs" and start saying "spaces" instead...

... And you'll get a much more practical perspective on the spaces-or-tabs problem. Any modern text editor is going to let you define tab width, and using spaces you're going to force a specific width on everyone dealing at your code.

I've heard some arguments with thoughtful, rational points on using spaces instead of tabs, but I am a bit offended by the "humans are change-resistant" point that seems to be made universally by people trying to shoehorn other people into doing something their way (e.g. systemd). Indeed, the only constant is change. All things are changing always. Nothing is static. This straw man argument is what people in the Quality Assurance industry call an "indicator" and it does not bode well for the people making it. It is a distant cousin of saying "Given the reasons X, Y, and Z for doing things this way, intelligent people will simply do it this way," which is a roundabout way of saying those who disagree are stupid.

In the end, my message to the spaces-over-tabs crowd is this: In this life, when we're interacting socially with members of a community -- especially members of a community who are striving together towards a common goal or against shared hardship -- we can't force onto others our preferences and opinions concerning minutiae. Attempting to do so will create friction and it may be that you can't recover from that mistake. You will drive a wedge between people who otherwise may work together in harmony. Is your army of spaces in front of every line that important after all?

Every package manager should be like npm.

And that's how I feel about package managers. Sure, there are other packages with many of the features of npm, and npm isn't a special snowflake. It could also really do a lot better with handling packages, perhaps with namespacing, and also by adding cryptographic signing capabilities. In my eyes, a large part of the success of Node is due to npm. Perhaps what I like most about npm is how easy it makes publishing packages. For the last, oh, four or five years, I've been a JavaScript programmer. I still write stuff in C in my spare time (I build robots), I spent my 20s writing perl, and the company I work for has a lot of PHP they are converting to Go. But I put food on the table using JavaScript. Incidentally, I tell people asking for my advice about becoming a programmer that if they learn JavaScript and Go they'll never go hungry. The caveat of course is that I'm telling them these things in the same way a bodybuilder tells a fat guy sharing an elevator ride how to get ripped: The conversation is going places reality probably won't follow, so even if it's bad advice, nobody gets hurt. And if you become a JS programmer, you're going to need some thick skin because JavaScript is so popular and ubiquitous, and this has caused tremendous butthurt in the world. But I digress.

The language you use can help or hinder your contributions to open source. JavaScript is helpful in this regard, with Node.js and its package manager, npm.

Let's say we've written a webhook module for a simple monitoring server. All it does is send a simple HTTP request on an event. For our purposes, our webhook module makes a call to Twilio's API when the monitoring server fires a "down server" event. It looks something like this:

module.exports = exports = __notify = (function() {
  var buffer = require('buffer');
  var https = require('https');
  var _down = function( config, server ) {
    // uh oh! server down! let's notify via Twilio's API
    var body = 'To=5125551212';
      body += '&From=+18005551212';
      body += '&Body=Server down (' + server.name + ')';
    var length = Buffer.byteLength(body);
    var options = {
      headers: {
        'Authorization': 'Basic ' + new Buffer(config.account + ':' + config.secret).toString('base64'),
        'Content-Length': length
      },
      hostname: 'api.twilio.com',
      port: 443,
      path: '/2010-04-01/Accounts/' + config.account + '/Messages.json',
      method: 'POST'
    };
    var req = https.request(options, function(res) {
      if (res.statusCode === 200) {
        console.log('Server down: Admin notified!');
      } else {
        console.log('Received strange response from API: ' + res.statusCode);
      }
    });
    req.on('error', function(e) {
      console.log('Error sending request: ' + e.message);
    });
    req.write( encodeURIComponent(body) );
  };
  return { down: _down };
})();

Our particular module isn't very amazing, but it gets the job done. It's also potentially a pretty versatile piece of code: With a little more work, we could make an entire webhook notifier library, with bindings for a few different notification APIs, for example AWS SNS and Sendgrid. I'm only mentioning these companies because I've used them in the past, but they're solid if you're looking for providers.

We've provided some utility and, in addition to creating a repository on Github and pushing our working code, we want to publish this as an npm package. This way anyone wanting to use our module can simply npm install fancynotify and use the module with a quick require(). This sounds like a lot of work, but on the contrary, this is where npm really shines.

First, we'll cd into the root directory of our project. Then, simply execute npm init and answer a few questions to generate a package.json file which we can use. Add and commit this file and any changes. When creating and publishing packages with npm, it is customary to tag a repository with its latest release version. We can do that with git tag -a v0.0.1 -m "v0.0.1: initial release". Now push your tags to Github with git push --tags origin master.

Now we're ready to interact with npm. Run npm adduser from your project's directory. You'll be prompted for a username, password, and email address. Once finished, npm will have created a config file in your home directory (~/.npmrc) which is used for interacting with npm, for example when you release a new version of your package. You can also check this file if you need a hint for your npm login details.

Finally, run npm publish and we're done. Congrats! You've just published a package with npm.

So this is my post about systemd...

My opinion is that systemd is not very good software, and that merit has almost nothing to do with its adoption. There is something hostile happening inside Red Hat, and I think systemd is a symptom of much deeper problems rather than just being substandard software written by a sociopath. My spidey sense is tingling on this one. You'll just have to trust me.