Reset the admin password on a FortiWiFi 60D

I recently got my hands on a nice Fortinet router that fell off the back of a truck. Getting access to it was way harder than it should have been. Here’s how you do it.

1) Install FortiExplorer. Connect the usb cable to the router and go to the web view. First just try ‘admin’ and no password. If that fails, you’ve gotta reset it.

3) Download a firmware from the Fortinet ftp server:

4) Upload the firmware to the router.

5) Unplug the power. Plug it back in and wait for the router to boot up.

6) Use a pen to hold the reset button for about 5 seconds within 30 seconds of the router booting up.

7) At this point I was unable to access the web view. Maybe try rebooting again and see if it works. If it does, you’re done.

8) Install the new firmware that you uploaded in step 4. Reboot and login with ‘admin’ and no password.

I posted my troubles on the network engineering stack exchange site and got a helpful yet dickish reply.

2014 Resolutions

In 2013 I made a few private resolutions.

  1. Run a marathon ✓
  2. Quit my job ✓
  3. Buy a piece of property ✕

#1 was easy. I’ve been milking that for months.

I left my role in engineering for the Labs team at Indeed, so I’m counting that as a win for #2.

I didn’t find any condos or homes that I loved, so I’m not losing any sleep over #3.

For 2014 I’m going to revisit my 2012 strategy of publicly declaring resolutions.

  1. Quit drinking for all of January.
  2. No news consumption.
  3. Read at least 24 books.
  4. Significant traction in a side project

I was considering going dry for all of Q1, but after floating the idea I’ve decided to table it. If you suggest this, people will look at you like you told them you were going to eat their pets.

The news thing is the big one. The “news is bad for you” meme is gaining some steam. I’ve written about it before. News includes pretty much anything useless on the internet. Exceptions are podcasts and audio editions of newspapers because there’s not much else to do in the car. Weekly digests are also fine.

If I can manage to pry myself away from the news, then reading will be a piece of cake. I enjoy it, but a rule helps me get into a flow state.

You’ve gotta have a stretch goal. For me, it’s getting a side project off the ground. “Significant” carries some ambiguity. I don’t want to limit myself to a revenue target. Unique visits or some other metric is acceptable. I’ll know it when I see it.

Dual boot Windows 8 and Ubuntu 12.04

Through a little trial and error I’ve made it work. This probably isn’t the only way, but it worked for me.

1) Install Windows on the beginning of the disk.
2) Install Ubuntu in a subsequent partition. Resize Windows with gparted if you need to.
3) At this point, only Ubuntu will be in the grub menu. Boot the Ubuntu install cd/usb again and install Boot-Repair. See the instructions under “2nd option”:
4) Run boot repair with the default settings. Pray to something holy. Reboot.

And finally, go into the Ubuntu update settings and check only the box for security releases. Updating everything is a recipe for disaster. If your system works, don’t mess with it unless you want to spend a Saturday during ACL troubleshooting nvidia drivers and an xorg.conf.

Control streaming audio on a remote PC with node.js

Over the weekend I got impatient waiting for my Chromecast to arrive so I built netbook-web-streamer. It’s a node.js app that loads URLs in an iframe on a remote PC that’s plugged into your large speakers. I use it to listen to playlists on songza and individual songs from youtube.

To play a song, enter it in the form on the homepage, or click the bookmarklet when you’re on a page you want the remote PC to load.

netbook audio streamer UI

How this works

There are 3 routes `’/’`, `’/loadUrl’`, and `’/audio’`.

`/` is the homepage. From there you can send xhr GET requests to `/loadUrl` with a `&url` param. The node.js view then broadcasts a event to a client that has loaded `/audio`. The event handler on the client takes the url value from the message and loads it in an iframe.

The only complication is that youtube forbids running videos on the main site in an iframe by sending an x-frame-options header. The workaround is to extract the video id from the url and turn it into an embed url.

Build an animated gif photo booth with HTML5 and JavaScript

I built an animated gif photobooth for the Indeed July 2013 hackathon.

Screen Shot 2013-07-19 at 2.14.51 PM

We got some good shots.

Gif photobeerhighfive

If you just want to run the app, the source is on GitHub: There’s no public demo because the code isn’t terribly secure and the images it produces are about 3mb each. But don’t let that stop you from playing with it.

If you want to implement something like this on your own, avoid Flash-based libraries like “jquery-webcam-plugin” or “scriptcam”. They’re a waste of time. New versions of Chrome let you do everything you want through Canvas and WebRTC’s Stream API.

First, read MDN’s excellent article, Taking webcam photos. They have annotated some JavaScript that shows how to grab a frame from a `<video>` stream, write it to a canvas, and `getImageData()` into the src attribute of an image element to display it on the page for a user.

I put some jQuery on top of their code to capture a bunch of frames in quick succession and POST the base-64 encoded data urls to a Flask backend. The Flask view  waits until it receives every frame in the set and stitches them together with ImageMagick.

The ImageMagick part is key. PIL and Pillow are huge timesucks for something this simple. ffmpeg is a nightmare. I dare you to look at its man page. If you ever want to create gifs, just use ImageMagick. It’s by far the easiest option.

Anyway, there are a few big issues with this project that are symptomatic of a hackathon. First, it takes a few CPU-intensive milliseconds in between image captures to load the canvas into a data url. This holds up the one and only thread, temporarily locking up the UI and preventing you from having a buttery smooth framerate. You could probably fix this with Web Workers. The other problem is that uploading 15 base64 strings containing medium-sized images takes longer than sending binary data like you would for a `multipart/form-data` file upload. You could get around this by writing the images to files with the File API and then uploading them from disk. And finally, the batches of images are grouped only by millisecond timestamp, so a unique identifier should be added if you want to get this ready for prime time.