I checked, the gem only has the Coffee source, no JavaScript. This frustrates the hell out of me -- clearly the message that you should ship JS is not getting through. When CS can do source maps, ideally people will ship the source, compiled JS and map together.
Having either in a gem is rare, but sensible if the gem wants to include a client to interact with the service it provides.
It is much less safe. PhantomJS has a filesystem API, which is fine when you consider that its primary use case is testing code you wrote and reporting the results. However, given that it is fairly easy to create a bridge between the PhantomJS and WebKit JavaScript runtimes, or to exploit common patterns for making such a bridge, running arbitrary 3rd-party code, loaded over a connection not verified by an SSL cert chain, is asking for trouble. This is an obvious backdoor to get write access to Meteor servers.
Never mind the cost. They are proposing that you run your app, with its 3rd-party jquery/facebook/twitter/google code loaded dynamically over non-SSL connections on a platform with filesystem-write-access to your server.
Relying on the way you happen to combine data, instead of using a function that's designed for authentication and has baked-in a safe way to combine the inputs, is a bad idea. "What if $EDGE_CASE_OF_INAPPROPRIATE_CRYPTO_FUNCTION" is never a good question to ask. Just use the right tools in the first place.
Your point about padding and length bytes is spot-on. I actually left this out of the explanation, although it's interesting, because I felt it a useless diversion: something that's safe except in an easily describable subset of cases is still not fit for purpose when specially designed tools without these problems exist.
Point being, although hash functions might work most of the time, their general construction does not make them safe for this purpose. You can't say something is 'mostly secure' because it works 'most of the time'. The times is doesn't work will affect someone, and for them the system is not secure at all.
Plus, implementations with weird edge cases make for horrible debugging, especially when it comes to security.
Possibly, although it depends on the lifetime of the link and the size of the tag (e.g. SHA-1 is 40 chars, each case requires mean of 8 guesses, so whole thing only requires 320 requests).
Better to have resistance as baked into your crypto as you can, rather than relying on a firewall further up the stack. If the data itself is resilient, no implementation will be able to defeat it efficiently.
In some cases, not letting them know they've failed is nice. But the most common case to look out for is, if your auth/crypto process involves multiple steps, don't return early from it, or do anything that alters its runtime significantly. This leaks useful information in many situations. The course at http://crypto-class.org is better than me at explaining this stuff, and starts on Monday.
Not the best, but most string comparison methods are designed to fail as soon as possible, which is not appropriate for this use case. Compare the entire input, or use some misdirection to destroy the relationship between correctness and time.
This is just one of the easier ways. It's effective and easy to code.
The timing attack is if you check the tag, that fails, and then you don't do any further request processing. This shortens the request time. It depends quite a lot on what you're actually doing with the message, but in general you want to leak as little info as possible about what's happening during any crypto-related process.
As someone who runs a lot of his own open-source projects (see http://jcoglan.com), and occasionally contributes to others when I find bugs, the biggest reason I do it is to learn things. Not just to learn programming, and various problem domains, but to practise writing and speaking about my work, writing good documentation, and (crucially) practising API design.
Making something you're intending to ship to strangers (or to yourself writing future projects with your tools) forces you to write good documentation (if you want anyone to use it), which in turn forces you to hone your API design skills. If you're having trouble writing the docs for something, you probably haven't adequately solved the problem yet.
I'm not claiming to have done a great job at this on all my projects, but it's a learning process and occasionally my projects find a user base, which keeps me busy, provides new challenges when they find bugs, and if your code's any good it boosts your reputation as a nice side effect.
I've been thinking about this. I might try out making all the primitive functions understand promises. So not lazy evaluation per se, but having the core library transparently deal with asynchronous values. Maybe monads would help but that really requires a decent type system.