The Monster Under Your Bed

Terry was wide awake, his eyes staring up at the ceiling. He’d heard a particular noise. A very familiar noise.

The sky outside clouded over, and the moonlight pooling on the bedsheets dried up. The room was dark. Steadily, the monster rose up from the end of his bed, darkening the room even more.

Two red eyes and a pitch-black silhouette was all that Terry could see of the beast. That noise, that deep, growling noise, reverberated throughout the room.

Terry had been going through this nearly every night for 8 years. And every night, he’d shrink into his bedsheets, shivering in fear, thinking that this time — THIS time — would be the time that the monster would finally put him out of his misery.

But it had been 8 years. And over time, the fear in Terry’s chest had lessened, and he began to think about his situation. Here was a terrifying creature, rising from the foot of his bed every night.

Sometimes it’d step towards him, slowly, its deep silhouette gradually sucking out the light surrounding it. The sheer dread, the constant threat, would leave Terry sobbing in anguish.

Sometimes it would be everywhere, the pitch black rising quickly, and Terry would wake up suddenly and realise that the dark creature had arrived.

But each and every night, Terry would fall asleep, unable to keep his eyes open for a single moment longer. And as he lost consciousness, there would be a deep, growling voice.

“Not tonight,” it would say.

But tonight, Terry wanted it to be different. He’d been living in fear for 8 years.

He took a deep breath, and rose up. He pushed aside his blankets, and pulled himself to the end of his bed.

Exhale.

Inhale.

Terry looked up. Staring into the consuming darkness, he could just about discern a hint of sharp, white teeth.

Here we go.

He felt his way around the silhouette, and clasped his hands around what he assumed to be the creature’s back. Soft skin and light fur met his touch. He buried his face into the shadow, and let the warmth of the creature wash over him.

Terry was fully expecting this to be the last thing he ever did. So when a clawed limb touched his back, he froze, anticipating the end.

Then, the creature placed another arm on his back, and in a single action, pulled him upwards, delivering a near-crushing hug.

The monster whispered:

“Thank you.”

TwineTubular – Twine macro for a YouTube background video

I’ve been quietly playing about with Twine recently. While working on something completely unrelated, I happened across this jQuery plugin called Tubular. I immediately thought it would be a cool thing to use in Twine games, after seeing how Porpentine has pulled off spectacular usage of YouTube-sourced audio in her games.

So I spent what turned out to be an entire sleepless night hacking jQuery and a jQuery plugin into the form of a Twine macro.

I have only tested this on the default Sugarcane template in Firefox 21 and Chrome 27. I can’t really provide any support, as I have no time to do so.

Here it is. Hope you’ll all get some use out of it.

Here’s a demo.

Update 2013-05-27: You can now use multiple videos in a single game (this didn’t work before as the plugin wasn’t cleaning up properly upon termination). You can now also use the audio from the YouTube video when you specify another argument.

After Posterous

Now that Posterous is leaving the building, I have moved this space to WordPress.com and a new domain name, jonathanprior.com. I’ve done this so I don’t need to fiddle around with updating a WordPress install which I’ll likely leave fallow for months to years on end.

And no, I still don’t really have time to blog. Every once in a while, though, I’ll churn out something. But my current attitude towards blogging hasn’t really changed.

PayPal, You Suck, Your API Sucks, And So Does Your Documentation

For the past two weeks I have been grappling with creating a PayPal integration for Gameolith. PayPal’s documentation (located at x.com) is frequently outdated, inaccurate, incomplete and even contradicts itself many a time. Their sandbox is buggy and broken, and went down shortly before I was about to launch, forcing me to delay its launch for more than a week.

This post documents my many trials and tribulations of dealing with their API, sandbox and documentation, in no particular order.

The documentation is disorganised and confusing

To make sense of the PayPal Express Checkout API, I downloaded 4 separate PDF files. I also referred to 3 pages off this API reference to do with Express Checkout operations. 

When it came to implementing IPN (Instant Payment Notification, basically a webhook) I had a hard time finding any information on the different payment statuses of an order on the PayPal X website. After looking it up on Google, I found it in a completely different part of the website.

I can’t set an NOTIFYURL (for IPN) in a SetExpressCheckout call

This makes IPN essentially useless in Express Checkout. Instead, I have to define a RETURNURL and set up a separate page (accessed by the user) to process the transaction and redirect the user as appropriate. I would rather do this in an IPN call.

GetExpressCheckoutDetails returns an undocumented value, CHECKOUTSTATUS

The GetExpressCheckoutDetails call returns a CHECKOUTSTATUS value rather than a PAYMENTSTATUS value, which is what I had come to expect after reading the NVP API reference. This post on the X.com forum reveals that CHECKOUTSTATUS is not a documented value, provides some information on it, and mentions that they’d “submitted a Doc update for this to be included in the guide”.

Last year.

What is CALLBACK for?

The NVP API reference defines CALLBACK as follows:

CALLBACK

(Optional) URLto which the callback request from PayPal is sent. It must startwith HTTPS for production integration. It can start with HTTPS orHTTP for sandbox testing.

Character length and limitations:1024 characters

But what on earth is the callback for? I assumed it sent back payment details to a URL of my choosing. But when I actually came to try and use it, I got an error which implied it was actually for postage calculations.

PayPal’s laughable lack of customer service

The day I was due to launch, which was July 14th 2011, I changed the PayPal credentials to the ones we would be using in production.

They didn’t work.

It failed because PayPal Express Checkout for Digital Goods hadn’t been activated on the account yet. Except I had rang them several days earlier to do just that, and they assured me it had been done. It hadn’t.

Cue a day full of phone calls, ringing PayPal to try and resolve it. I rang Customer Service (who I had contacted the other day), and they directed me to another number, which turned out to be telesales. Telesales directed me to Merchant Technical Support. Merchant Technical Support sent me right back to Telesales again. I filled out a form on the PayPal website, ostensibly about signing up for Digital Goods, and got an e-mail back welcoming me to PayPal, as if I didn’t have an account already. I replied to the e-mail asking them to activate my account, and got another phone call with a lady telling me I needed help with my integration, which I didn’t, BECAUSE IT WAS OTHERWISE WORKING PERFECTLY.

So the woman told me I would receive a phone call the next morning from the Integration team. I put out messages on Twitter, Facebook, and e-mailed all my partners to let them know I had to delay the launch yet again. And I must say that the response was outstanding.

Django: How to use the permission_required decorator with the method_decorator in a class-based view

Since the documentation on the method_decorator in Django is quite confusing, and Google didn’t turn up any useful results for me, I had to resort to trial and error to work out how to use the permission_required decorator in class-based views.

If the decorator doesn’t accept the view as an argument, you can just call it as a method. You just need to wrap the dispatch() method as normal.

@method_decorator(permission_required(‘products.change_game’))
def dispatch(self, *args, **kwargs):
        return super(MyView, self).dispatch(*args, **kwargs)

That’s it.

On Keeping Your Users

Zed Shaw brought up a good point about yesterday’s post on user-friendly registration, the fact that through handing off authentication to a third party, you would be handing off control of your users.

However, you can take precautions which will keep some semblance of control over your users and their login flows. You need a ‘I Cannot Login’ link. It’s like a ‘Forgot Password’ link, but the process would involve removing external authentication and replacing it with the traditional password (if it isn’t used already). This is because it’s pretty much impossible to remotely diagnose a faulty external auth provider.

Then you should build this functionality into your backend, but allow for batches of users to have their external auth details revoked. The next time they attempt to login, they will be prompted to add a new password (after checking their e-mail for a verification link, of course). This means you can quickly deal with users who are authenticating against a provider who has (for example) blocked your service.

Of course, the other problem with implicitly trusting external auth at all is that if the auth server gets hacked and starts logging sessions, it could steal your users accounts. The only real way around this is to have a whitelist of providers. Again, this begets some trust. You can also allow users to link a different provider to their account, but you should be careful not to make this too confusing.

In the end, all the users who don’t have external auth available will be asked for a password. That is inherently problematic if you don’t want to store passwords. Zed Shaw’s Autho.me is a step in the right direction, although not ready for general use. But using bcrypt and SSL is the current best practice until we can come up with the best replacement.

Once more, it boils down to the trust problem. It’s really up to you whether you mind handing over some control of your registration/login flow to a third party. It’s not the best solution to the age-old problem of easy login, but I think it’s the best we have right now. In terms of sheer convenience — not having to create new passwords for everything for the user, not needing to store passwords for all users for the developer — it’s a no-brainer. But from a security point of view, you should take reasonable precautions, and when things go wrong you can deal with them quickly and effectively.