source: bookmarks/trunk/lib/BookmarksApp.pm @ 115

Last change on this file since 115 was 114, checked in by peter, 9 years ago

Store user credentials in an external htdigest file.

File size: 4.8 KB
Line 
1package BookmarksApp;
2
3=head1 NAME
4
5BookmarksApp
6
7=head1 SYNOPSIS
8
9    use BookmarksApp;
10    use Digest::MD5 qw{md5_hex};
11
12    my $username = '...';
13    my $password = '...';
14    my $app = BookmarksApp->new({
15        config => {
16            dbname => 'bookmarks.db',
17
18            # set these if you want non-GET requests to require authentication
19            auth            => 1,
20            digest_key      => 'secret',
21            digest_password => md5_hex("$username:Bookmarks:$password"),
22           
23            # set this if the app is running behind a proxy server
24            proxy_ip  => '...',
25        },
26    });
27
28    # returns the coderef appropriate for use in an app.psgi,
29    # or for passing the Plack::Runner, etc.
30    $app->to_app;
31
32=cut
33
34use strict;
35use warnings;
36
37use parent qw{Plack::Component};
38use Plack::Util::Accessor qw{config _app _controller};
39
40use YAML;
41use Plack::Builder;
42use Plack::Request;
43use Router::Resource;
44
45use Bookmarks::Controller;
46
47sub prepare_app {
48    my $self = shift;
49
50    my $config = $self->config;
51
52    my $router = router {
53        resource '/' => sub {
54            GET {
55                # check for a uri param, and if there is one present,
56                # see if a bookmark for that URI already exists; if so
57                # redirect to that bookmark, and if not, show the form
58                # to create a new bookmark
59                if (defined $self->_controller->request->param('uri')) {
60                    return $self->_controller->find_or_new;
61                }
62
63                # otherwise return the sidebar
64                return $self->_controller->sidebar;
65            };
66            POST {
67                # create the bookmark and redirect to the new bookmark's edit form
68                return $self->_controller->create_and_redirect;
69            };
70        };
71
72        resource '/list' => sub {
73            GET {
74                return $self->_controller->list;
75            };
76        };
77
78        resource '/feed' => sub {
79            GET {
80                return $self->_controller->feed;
81            };
82        };
83
84        resource '/tags' => sub {
85            GET {
86                my ($env, $params) = @_;
87                return $self->_controller->tag_tree;
88            };
89        };
90        resource '/tags/*' => sub {
91            GET {
92                my ($env, $params) = @_;
93                my $tag_path = (@{ $params->{splat} })[0];
94                return $self->_controller->tag_tree([ split m{/}, $tag_path ]);
95            };
96        };
97
98        resource '/{id}' => sub {
99            GET {
100                my ($env, $params) = @_;
101                return $self->_controller->view($params->{id});
102            };
103            POST {
104                my ($env, $params) = @_;
105                return $self->_controller->update_and_redirect($params->{id});
106            };
107        };
108
109        resource '/{id}/{field}' => sub {
110            GET {
111                my ($env, $params) = @_;
112                return $self->_controller->view_field($params->{id}, $params->{field});
113            };
114        };
115
116    };
117
118    # if configured for auth, read in the htdigest database file
119    # and store the password hashes keyed by username
120    my %password_hash_for;
121    if ($config->{auth}) {
122        $config->{realm} ||= 'Bookmarks';
123        $config->{htdigest} or die "No htdigest configured for authentication\n";
124        open my $htdigest, '<', $config->{htdigest} or die "Can't open $$config{htdigest}\n";
125        while (my $credentials = <$htdigest>) {
126            chomp $credentials;
127            my ($username, $realm, $password_hash) = split /:/, $credentials;
128            # only add password digests for the configured realm
129            if ($realm eq $config->{realm}) {
130                $password_hash_for{$username} = $password_hash;
131            }
132        }
133        close $htdigest;
134    }
135
136    $self->_app(
137        builder {
138            enable_if { $_[0]->{REMOTE_ADDR} eq $config->{proxy_ip} } 'ReverseProxy'
139                if $config->{proxy_ip};
140            enable_if { $_[0]->{REQUEST_METHOD} ne 'GET' } 'Auth::Digest', (
141                realm           => $config->{realm},
142                secret          => $config->{digest_key},
143                password_hashed => 1,
144                authenticator   => sub {
145                    my ($username, $env) = @_;
146                    return $password_hash_for{$username};
147                },
148            ) if $config->{auth};
149            sub { $router->dispatch(shift); };
150        }
151    );
152    $self->_controller(
153        Bookmarks::Controller->new({
154            dbname  => $self->config->{dbname},
155        })
156    );
157}
158
159sub call {
160    my $self = shift;
161    my $env = shift;
162
163    # initialize the controller based on this request
164    $self->_controller->request(Plack::Request->new($env));
165
166    # dispatch to the app
167    $self->_app->($env);
168}
169
170# module return
1711;
172
173=head1 AUTHOR
174
175Peter Eichman <peichman@cpan.org>
176
177=cut
Note: See TracBrowser for help on using the repository browser.