Humanity

Edit the world by your favorite way

はてブのバックアップを取りたい

と衝動的に思ったのでやろうとした。
まぁcronとwgetで適当に取ってくればいいだろうと思って設定ページ見たら
どうやらWSSE認証というのが必要らしい。
なんぞと思いながらググってみるとこのページがひっかかった。
はてなフォトライフAtomAPIとは - はてなキーワード


ありがたいことにPerlでの実装例が書いてある。
ということでコピペして色々いじったものがこちら。

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;

use Getopt::Long;
use Perl6::Say;
use Pod::Usage;
use DateTime;
use Digest::SHA1 qw( sha1 );
use HTTP::Request;
use MIME::Base64 qw( encode_base64 );
use LWP::UserAgent;
use Term::ReadPassword;


my ($username, $password, $needhelp, $filepath, $mode);
GetOptions(
    'user=s'   => \$username,
    'pass=s'   => \$password,
    help       => \$needhelp,
    'output=s' => \$filepath,
    'mode=s'   => \$mode,
) or pod2usage( -verbose => 1 );
pod2usage( -verbose => 1 )   if $needhelp;

# set default
unless( defined $username ) {
    print "put your hatena username:";
    chomp( $username = <STDIN> );
}
until( defined $password ) {
    $password = read_password( "put your password:" );
}
unless( defined $filepath ) {
    $filepath = "./hatebu.txt";
}
if( defined $mode ) {
    if( $mode !~ /(rss|bookmarks)?/ ) {
        say "use default";
        $mode = "bookmarks";
    }
} else {
    $mode = "bookmarks";
}

# wsse authentication
my $nonce = sha1( sha1( time() . {} . rand() . $$ ) );
my $now = DateTime->now->iso8601 . 'Z';
my $digest = encode_base64( sha1( $nonce . $now . $password || '' ), '' );
my $credentials =
    sprintf( qq(UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s"),
            $username, $digest,  encode_base64( $nonce, '' ), $now );

my $url = 'http://b.hatena.ne.jp/dump' . ( $mode eq "" ? "" : "?mode=$mode" );
my $req = HTTP::Request->new( GET => $url );
$req->header( Accept => 'application/x.atom+xml, application/xml, text/xml, */*' );
$req->header( 'X-WSSE' => $credentials );

# saving data
my $ua = LWP::UserAgent->new;
$ua->show_progress( 1 );
my $res = $ua->request( $req );
unless( $res->is_success ) {
    die $res->status_line . "\n";
}
my $FH = FileHandle->new( "> $filepath" );
unless( defined $FH ) {
    die "can't open '$filepath'.\n";
}
print $FH $res->content;
$FH->close;


say "Done.";
__END__

=head1 NAME
hatebu-backup - backup hatena bookmarks


=head1 SYNOPSIS
hatebu-backup [-u user] [-p password] [-o output-file] [-m mode] [-h]


=head1 OPTIONS

=over 5

=item -u, --user

specify hatena username.

=item -p, --pass

specify hatena password.

=item -h, --help

show help.

=item -o, --output

specify output file path.

=item -m, --mode

specify hatena bookmark file mode.(r[ss], b[ookmarks] are allowed)

=back

あとさっきのページにも書いてあったけど
LWP::Authen::Wsseというのを使えばかなり短く書けそう・・・なんだけどインストールに失敗したorz
それと最近はパスワードを管理するにはConfig::Pitを使うのかな?とか思ったけどそれもインストール失敗・・・(Cygwinだから?

まぁとりあえず目的は達成できたのでよしとする。