HN user

jcoglan

67 karma
Posts3
Comments31
View on HN

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.

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.

I was going to do call/cc but fibers are cheaper. The implementation is very similar, but because fibers can only be resumed once from the last yield you don't need to copy the stack when yielding and resuming.

They also require the user to explicitly start a fiber. This means when you're not in a fiber you can use a faster stackless engine because you don't need to track the state of the current continuation.

Songkick (YC'07, London) is hiring again. We're a small company (about 20 people) that's working to improve the live music scene for everyone involved. We help fans track their favourite artists so they never miss them live, and we help artists get the word out about upcoming shows.

In the last year we've seen tremendous growth in our user base and with our commercial partnerships, including integrations with YouTube and Yahoo! Search. We just launched our first major label integration with EMI and are working on plenty more. There's a lot of work to do scaling our team and our technology stack, making it a really exciting time to join us.

If you, or someone you know, is an experienced and fast-learning developer into TDD and scalable web services we'd love to hear from you. We have a great team that's a joy to work with (you may have met a few of us at Ruby events), and we have a lot of challenging projects on our roadmap.

If you're interested, check out our jobs page at http://www.songkick.com/info/jobs and get in touch with our COO Pete Smith at pete@songkick.com

I wrote a Scheme in Ruby that has macros last year: http://github.com/jcoglan/heist. It's an interpreter, not a compiler, and is extremely dynamic: all functions, macros, special forms are just treated as function calls by the parser. Macros are just a subtype of functions that accept and return syntax nodes before eval-ing the output, and this is done at runtime while running all your regular code.

Scheme in Ruby. 16 years ago

The rationale is that I wanted to learn how to write an interpreter, particularly some of the more challenging parts like tail recursion, macros, continuations and laziness. It's in Ruby because that's what I know best; it's not intended for production use as a replacement for Ruby, though I have used it myself to do a little code transformation and testing in Ruby apps.

So basically it's a toy, but one that I hope others can learn something from.

You're missing a few details, especially around "primitive" data types. There's not really any such thing in Ruby - everything is an object, but some objects - numbers, booleans, nil - are immutable.

When you copy an object, all you do is copy its set of instance variables, which are just references to other objects. For an array, the instance variables are its set of indexes, which again are just references. Copying an array just means making a new list of references, but the objects they point to remain unmodified and uncopied.

Consider:

<pre> array = ["foo"] copy = array.dup </pre>

array and copy are independently mutable - modifying the index in one does not affect the indexes in the other - but they still both contain references to the single string "foo". Thus:

<pre> copy.first.gsub! /foo/, "bar" </pre>

modifies the string referenced by copy, which is the same string referenced by array. So array becomes ["bar"].

If you want a true deep copy, do something like this:

<pre> def deep_copy(object) case object when Array object.map { |item| deep_copy(item) } when Hash object.inject({}) do |hash, (key,value)| hash[deep_copy(key)] = deep_copy(value) hash end # handle other data structures if need be else object.respond_to?(:dup) ? object.dup : object end end </pre>

Rest assured it will have more thorough documentation at some point, for my own benefit as much as anyone else's. Right now it's all very new and its internals are not that stable, so the only comments tend to be for stuff that followed a long debugging session to remind me why certain things are there. When it's more stable I'll do a better job of writing up how it works.

You'd be right to be terrified, it's not exactly zippy. It's a toy, but I'm releasing it because it's got a couple of nice features (friendly REPL, lazy evaluation) and it's more complete in some areas than other toy Schemes I've tried. Also I figured it might be a nice example implementation for people who know Ruby. If you have optimisation suggestions or links to stuff I should read on the subject I'd be delighted.