File Coverage

blib/lib/App/Spoor/Security.pm
Criterion Covered Total %
statement 39 39 100.0
branch 10 10 100.0
condition 4 8 50.0
subroutine 8 8 100.0
pod 5 5 100.0
total 66 70 94.2


line stmt bran cond sub pod time code
1             package App::Spoor::Security;
2              
3 1     1   166882 use v5.10;
  1         7  
4 1     1   8 use strict;
  1         2  
  1         27  
5 1     1   4 use warnings;
  1         2  
  1         421  
6              
7             =head1 NAME
8              
9             App::Spoor::Security
10              
11             =head1 VERSION
12              
13             Version 0.01
14              
15             =cut
16              
17             our $VERSION = '0.01';
18              
19             =head1 SYNOPSIS
20              
21             Performs rudimentary permission and ownership checks of Spoor-related files and directories
22              
23             =head1 SUBROUTINES
24              
25             =head2 check_config_file
26              
27             Checks that the spoor config file is owner by the specified user and has permissions '0600'.
28              
29             App::Spoor::Security::check_config_file($<) || die("blah blah blah");
30              
31             # Optionally, you can pass in an alternative to the root path '/' which is used when building the path
32             # to the config file. In the code snippet below, the code will look for the config file in
33             # /tmp/etc/spoor/ instead of /etc/spoor. This is primarily used to support testing.
34             App::Spoor::Security::check_config_file($<, '/tmp') || die("blah blah blah");
35              
36             =cut
37              
38             sub check_config_file {
39 3     3 1 6651 my $required_user_id = shift;
40 3   50     14 my $root_path = shift @_ // '/';
41              
42 3         40 my @file_stat = stat "$root_path/etc/spoor/spoor.yml";
43 3         8 my $file_user_id = $file_stat[4];
44 3         6 my $file_permissions = $file_stat[2] & 07777;
45            
46 3 100       30 $file_user_id == $required_user_id && $file_permissions == 0600;
47             }
48              
49             =head2 check_file
50              
51             Checks that a given file is owned by the specified user and has the permissions specified.
52              
53             App::Spoor::Security::check_file(shift, $>, 0600) || die("blah blah blah");
54              
55             =cut
56              
57             sub check_file {
58 3     3 1 6986 my $path = shift;
59 3         17 my $required_user_id = shift;
60 3         9 my $required_permissions = shift;
61              
62 3         43 my @stat = stat $path;
63 3         8 my $user_id = $stat[4];
64 3         6 my $permissions = $stat[2] & 07777;
65            
66 3 100       45 $user_id == $required_user_id && $permissions == $required_permissions;
67             }
68              
69             =head2 check_config_directory
70              
71             Checks that the spoor config directory is owned by the specified user and has permissions '0700'.
72              
73             App::Spoor::Security::check_config_directory($<) || die("blah blah blah");
74              
75             # Optionally, you can pass in an alternative to the root path '/' which is used when building the path
76             # to the config file. In the code snippet below, the code will look for the config directory in
77             # /tmp/etc/ instead of /etc. This is primarily used to support testing.
78             App::Spoor::Security::check_config_directory($<, '/tmp') || die("blah blah blah");
79              
80             =cut
81              
82             sub check_config_directory {
83 3     3 1 5474 my $required_user_id = shift;
84 3   50     12 my $root_path = shift @_ // '/';
85              
86 3         47 my @stat = stat "$root_path/etc/spoor";
87 3         9 my $user_id = $stat[4];
88 3         7 my $permissions = $stat[2] & 07777;
89            
90 3 100       26 $user_id == $required_user_id && $permissions == 0700;
91             }
92              
93             =head2 check_persistence_directory
94              
95             Checks that the spoor persistence directory is owned by the specified user and has permissions '0700'.
96              
97             App::Spoor::Security::check_persistence_directory($<) || die("blah blah blah");
98              
99             # Optionally, you can pass in an alternative to the root path '/' which is used when building the path
100             # to the config file. In the code snippet below, the code will look for the persistence directory in
101             # /tmp/var/lib instead of /var/lib. This is primarily used to support testing.
102             App::Spoor::Security::check_persistence_directory($<, '/tmp') || die("blah blah blah");
103              
104             =cut
105              
106             sub check_persistence_directory {
107 3     3 1 5940 my $required_user_id = shift;
108 3   50     13 my $root_path = shift @_ // '/';
109              
110 3         51 my @stat = stat "$root_path/var/lib/spoor";
111 3         10 my $user_id = $stat[4];
112 3         10 my $permissions = $stat[2] & 07777;
113            
114 3 100       34 $user_id == $required_user_id && $permissions == 0700;
115             }
116              
117             =head2 check_parsed_persistence_directory
118              
119             Checks that the spoor parsed persistence directory is owned by the specified user and has permissions '0700'.
120              
121             App::Spoor::Security::check_persistence_directory($<) || die("blah blah blah");
122              
123             # Optionally, you can pass in an alternative to the root path '/' which is used when building the path
124             # to the config file. In the code snippet below, the code will look for the parsed items directory in
125             # /tmp/var/lib/spoor instead of /var/lib/spoor. This is primarily used to support testing.
126             App::Spoor::Security::check_persistence_directory($<, '/tmp') || die("blah blah blah");
127              
128             =cut
129              
130             sub check_parsed_persistence_directory {
131 3     3 1 6267 my $required_user_id = shift;
132 3   50     14 my $root_path = shift @_ // '/';
133              
134 3         47 my @stat = stat "$root_path/var/lib/spoor/parsed";
135 3         11 my $user_id = $stat[4];
136 3         6 my $permissions = $stat[2] & 07777;
137            
138 3 100       32 $user_id == $required_user_id && $permissions == 0700;
139             }
140              
141             =head1 AUTHOR
142              
143             Rory McKinley, C<< <rorymckinley at capefox.co> >>
144              
145             =head1 BUGS
146              
147             Please report any bugs or feature requests to C<bug-. at rt.cpan.org>, or through
148             the web interface at L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=.>. I will be notified, and then you'll
149             automatically be notified of progress on your bug as I make changes.
150              
151              
152             =head1 SUPPORT
153              
154             You can find documentation for this module with the perldoc command.
155              
156             perldoc App::Spoor::Security
157              
158              
159             You can also look for information at:
160              
161             =over 4
162              
163             =item * RT: CPAN's request tracker (report bugs here)
164              
165             L<https://rt.cpan.org/NoAuth/Bugs.html?Dist=.>
166              
167             =item * AnnoCPAN: Annotated CPAN documentation
168              
169             L<http://annocpan.org/dist/.>
170              
171             =item * CPAN Ratings
172              
173             L<https://cpanratings.perl.org/d/.>
174              
175             =item * Search CPAN
176              
177             L<https://metacpan.org/release/.>
178              
179             =back
180              
181             =head1 LICENSE AND COPYRIGHT
182              
183             Copyright 2019 Rory McKinley.
184              
185             This program is free software; you can redistribute it and/or modify it
186             under the terms of the the Artistic License (2.0). You may obtain a
187             copy of the full license at:
188              
189             L<http://www.perlfoundation.org/artistic_license_2_0>
190              
191             Any use, modification, and distribution of the Standard or Modified
192             Versions is governed by this Artistic License. By using, modifying or
193             distributing the Package, you accept this license. Do not use, modify,
194             or distribute the Package, if you do not accept this license.
195              
196             If your Modified Version has been derived from a Modified Version made
197             by someone other than you, you are nevertheless required to ensure that
198             your Modified Version complies with the requirements of this license.
199              
200             This license does not grant you the right to use any trademark, service
201             mark, tradename, or logo of the Copyright Holder.
202              
203             This license includes the non-exclusive, worldwide, free-of-charge
204             patent license to make, have made, use, offer to sell, sell, import and
205             otherwise transfer the Package with respect to any patent claims
206             licensable by the Copyright Holder that are necessarily infringed by the
207             Package. If you institute patent litigation (including a cross-claim or
208             counterclaim) against any party alleging that the Package constitutes
209             direct or contributory patent infringement, then this Artistic License
210             to you shall terminate on the date that such litigation is filed.
211              
212             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
213             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
214             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
215             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
216             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
217             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
218             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
219             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
220              
221              
222             =cut
223              
224             1; # End of App::Spoor::Security