summaryrefslogtreecommitdiff
path: root/libpiny
diff options
context:
space:
mode:
Diffstat (limited to 'libpiny')
-rw-r--r--libpiny/lib/Piny/Config.pm4
-rw-r--r--libpiny/lib/Piny/Repo.pm209
2 files changed, 171 insertions, 42 deletions
diff --git a/libpiny/lib/Piny/Config.pm b/libpiny/lib/Piny/Config.pm
index a1813d4..1da5631 100644
--- a/libpiny/lib/Piny/Config.pm
+++ b/libpiny/lib/Piny/Config.pm
@@ -49,8 +49,8 @@ subtype 'HttpsUrl'
subtype 'RepoPermission'
=> as 'Str'
- => where { $_ eq "0666" or $_ eq "0664" or $_ eq "0660" or $_ eq "0640" or $_ eq "group" or $_ eq "true" or $_ eq "false" or $_ eq "all" or $_ eq "everybody" or $_ eq "world"}
- => message { 'Must be one of 0666, 0664 (or all, everybody, world), 0660 (or true, group), or 0640 (or false).' }
+ => where { $_ eq "0666" or $_ eq "0664" or $_ eq "0660" or $_ eq "0640" or $_ eq "group" or $_ eq "true" or $_ eq "false" or $_ eq "all" or $_ eq "everybody" or $_ eq "world" or $_ eq "1" or $_ eq "2" }
+ => message { 'Must be one of 0666, 0664 (or all, everybody, world), 0660 (or true, 1, group), or 0640 (or false, 0).' }
;
# Attributes
diff --git a/libpiny/lib/Piny/Repo.pm b/libpiny/lib/Piny/Repo.pm
index 3bb275d..8c38323 100644
--- a/libpiny/lib/Piny/Repo.pm
+++ b/libpiny/lib/Piny/Repo.pm
@@ -174,7 +174,21 @@ has 'secure_path' =>
, init_arg => undef
);
-has 'apache_config' =>
+has 'apache_global_config' =>
+ ( is => 'ro'
+ , isa => 'Str'
+ , lazy_build => 1
+ , init_arg => undef
+ );
+
+has 'apache_secure_config' =>
+ ( is => 'ro'
+ , isa => 'Str'
+ , lazy_build => 1
+ , init_arg => undef
+ );
+
+has 'apache_www_config' =>
( is => 'ro'
, isa => 'Str'
, lazy_build => 1
@@ -224,6 +238,9 @@ sub rebuild {
sub rebuild_git {
my ( $s ) = @_;
+ my $dirperm;
+ my $fileperm;
+
unless( getgrnam("git-" . $s->shortname ) ) {
system( "/usr/sbin/addgroup", "--quiet", "git-" . $s->shortname ) and die "Could not create repo group!";
system( "/usr/sbin/adduser", "--quiet", $s->owner->name, "git-" . $s->shortname ) and die "Could not add you to the repo group!";
@@ -237,20 +254,45 @@ sub rebuild_git {
};
};
- chown( 0, 0, $s->path, $s->path . "/config" ) or die "Could not change ownership of git config!";
-
foreach( "info", "logs", "branches" ) {
(-e $s->path . "/" . $_) or mkdir( $s->path . "/" . $_ ) or die "Could not mkdir $_ for repo: $!";
};
- foreach( "branches", "description", "HEAD", "info", "logs", "objects", "packed-refs", "refs" ) {
- system( "/bin/chown", "-R", $s->owner->name . "." . $s->group->name, $s->path . "/" . $_ ) and die "Could not change ownership of $_ for repo: $!";
+ if ( $s->config->core_sharedrepository eq "0666" ) {
+ $dirperm = "2777";
+ $fileperm = "0644";
+ } elsif ( $s->config->core_sharedrepository =~ /^(0664|all|everybody|world)$/ ) {
+ $dirperm = "2775";
+ $fileperm = "0644";
+ } elsif ( $s->config->core_sharedrepository =~ /^(0660|true|1|group)$/ ) {
+ $dirperm = "2770";
+ $fileperm = "0640";
+ } elsif ( $s->config->core_sharedrepository =~ /^(0640|false|0)$/ ) {
+ $dirperm = "2750";
+ $fileperm = "0640";
+ } else {
+ die $s->config->core_sharedrepository . "is an unhandled value!"
+ };
+
+ # FIXME: we should verify we are not breaking someone else's object hardlinks with these chmod or chown operations
+ system( "/usr/bin/find " . $s->path . "/refs " . $s->path . "/info " . $s->path . "/branches " . $s->path . "/objects " . $s->path . "/logs " . $s->path . "/HEAD " . $s->path . "/packed-refs -type d -print0 | /usr/bin/xargs -0 /bin/chmod $dirperm" ) and die "Could not chmod shared git resources!";
+ system( "/usr/bin/find " . $s->path . "/refs " . $s->path . "/info " . $s->path . "/branches " . $s->path . "/objects " . $s->path . "/logs " . $s->path . "/HEAD " . $s->path . "/packed-refs -type f -print0 | /usr/bin/xargs -0 /bin/chmod $fileperm" ) and die "Could not chmod shared git resources!"; # most files are either immutable or replaced at link level
+ system( "/usr/bin/find " . $s->path . "/refs " . $s->path . "/info " . $s->path . "/branches " . $s->path . "/objects " . $s->path . "/logs " . $s->path . "/HEAD " . $s->path . "/packed-refs -print0 | /usr/bin/xargs -0 /bin/chgrp " . $s->group->name ) and die "Could not chgrp shared git resources!";
+
+ chown( 0, 0, $s->path ) or die "Could not change ownership of " . $s->path;
+ chmod( 00755, $s->path ) or die "Could not change mode of " . $s->path;
+
+ foreach( "config", "description", "git-daemon-export-ok" ) {
+ chown( 0, 0, $s->path . "/" . $_ ) or die "Could not change ownership of $_!";
+ chmod( 00644, $s->path . "/" . $_ ) or die "Could not change mode of $_!";
};
$ENV{"GIT_DIR"} = $s->path;
system( "/usr/bin/git", "config", "gitweb.owner", $s->owner->email->address ) and die "Could not git config gitweb.owner!";
# packed-refs files aren't modifiable under our permission system and are poorly supported on old version of git anyway.
system( "/usr/bin/git", "config", "gc.packrefs", "0" ) and die "Could not git config gc.packrefs!";
+ # git-upload-pack will default to core.sharedrepository 'false', so we make sure the pinyconfig value is set here.
+ system( "/usr/bin/git", "config", "core.sharedrepository", $s->config->core_sharedrepository ) and die "Could not git config core.sharedrepository!";
delete $ENV{"GIT_DIR"};
$s->clear_config;
@@ -274,15 +316,16 @@ sub rebuild_ikiwiki {
print SETUP $s->ikiwiki_setup;
close( SETUP ) or die "Could not close new ikiwiki setup file: $!";
- unless( -d $s->ikiwiki_srcdir ) {
- system( "/usr/bin/git", "clone", "--quiet", $s->path, $s->ikiwiki_srcdir ) and die "Could not clone repo to ikiwiki srcdir!";
+ foreach( $s->ikiwiki_srcdir, $s->config->piny_ikiwikidestdir . $s->name, $s->ikiwiki_destdir, $s->secure_path ) {
+ unless( -d $_ ) { mkdir( $_ ) };
+ system( "/bin/chown", "-R", $ikiuser->name . ".", $_ ) and die "Could not change ownership of ikiwiki directories!";
};
system( "/usr/bin/find " . $s->ikiwiki_srcdir . " -type d -name .ikiwiki -print0 | xargs -0 --no-run-if-empty rm -r") and die "Could not remove old Ikiwiki state dir!";
- foreach( $s->ikiwiki_srcdir, $s->ikiwiki_destdir, $s->secure_path ) {
- unless( -d $_ ) { mkdir( $_ ) };
- system( "/bin/chown", "-R", $ikiuser->name . ".", $_ ) and die "Could not change ownership of ikiwiki directories!";
+ unless( -d $s->ikiwiki_srcdir . ".git" ) {
+ # do this after the chown -R because there are a lot of object hardlinks flying around that don't want to chown
+ system( "/usr/bin/sudo", "-u", $ikiuser->name, "/usr/bin/git", "clone", "--quiet", $s->path, $s->ikiwiki_srcdir ) and die "Could not clone repo to ikiwiki srcdir!";
};
open( WIKILIST, ">", "/etc/ikiwiki/wikilist.d/" . $s->name ) or die "Could not create wikilist.d file: $!";
@@ -293,12 +336,23 @@ sub rebuild_ikiwiki {
system( "/usr/bin/sudo", "-u", $ikiuser->name, "/usr/bin/ikiwiki", "--setup", "/etc/ikiwiki/piny/" . $s->name . ".setup" ) and die "Could not do initial compile of ikiwiki!";
- open( APACHE, ">", "/etc/apache2/piny-available/" . $s->name ) or die "Could not open new apache config: $!";
- print APACHE $s->apache_config;
- close( APACHE ) or die "Could not close new apache config: $!";
+ my $globaltemp = File::Temp->new( ) or die "Could not create temporary file: $!";
+ $globaltemp->unlink_on_destroy( 0 );
+ print $globaltemp $s->apache_global_config;
+ $globaltemp->close or die "Could not close new wikilist: $!";
+ rename( $globaltemp->filename, "/etc/apache2/piny/global/" . $s->name ) or die "Could not rename apache config: $!";
+
+ my $securetemp = File::Temp->new( ) or die "Could not create temporary file: $!";
+ $securetemp->unlink_on_destroy( 0 );
+ print $securetemp $s->apache_secure_config;
+ $securetemp->close or die "Could not close new wikilist: $!";
+ rename( $securetemp->filename, "/etc/apache2/piny/secure/" . $s->name ) or die "Could not rename apache config: $!";
- unlink( "/etc/apache2/piny-enabled/" . $s->name );
- symlink( "/etc/apache2/piny-available/" . $s->name, "/etc/apache2/piny-enabled/" . $s->name ) or die "Could not symlink apache config: $!";
+ my $wwwtemp = File::Temp->new( ) or die "Could not create temporary file: $!";
+ $wwwtemp->unlink_on_destroy( 0 );
+ print $wwwtemp $s->apache_www_config;
+ $wwwtemp->close or die "Could not close new wikilist: $!";
+ rename( $wwwtemp->filename, "/etc/apache2/piny/www/" . $s->name ) or die "Could not rename apache config: $!";
system( "/etc/init.d/apache2", "reload" ) and die "Could not reload apache config!";
};
@@ -340,7 +394,7 @@ sub destroy_ikiwiki {
my $user = Piny::Environment->instance->user;
- foreach( "/etc/apache2/piny-enabled/" . $s->name, "/etc/apache2/piny-available/" . $s->name, ) {
+ foreach( "/etc/apache2/piny/global/" . $s->name, "/etc/apache2/piny/secure/" . $s->name, "/etc/apache2/piny/www/" . $s->name, ) {
if ( -e $_ ) {
unlink( $_ );
};
@@ -353,7 +407,7 @@ sub destroy_ikiwiki {
$s->rebuild_wikilist;
};
- foreach( $s->secure_path, $s->ikiwiki_destdir, $s->ikiwiki_srcdir, "/etc/ikiwiki/piny/" . $s->name . ".setup" ) {
+ foreach( $s->secure_path, $s->config->piny_ikiwikidestdir . $s->name, $s->config->piny_ikiwikisecurepath . "read/" . $s->name, $s->ikiwiki_destdir, $s->ikiwiki_srcdir, "/etc/ikiwiki/piny/" . $s->name . ".setup" ) {
if ( -e $_ ) {
system( "rm", "-rf", $_ );
};
@@ -417,18 +471,19 @@ sub create {
mkdir( $repo->path ) or die "The repo $name appears to already exist! ($!)";
- $ENV{"GIT_DIR"} = $repo->path;
- system( "/usr/bin/git", "init", "--bare", "--quiet", "--shared" ) and die "Could not initialize git repo!";
- delete $ENV{"GIT_DIR"};
-
- system( "/bin/chown", "-R", $user->name, $repo->path . "/objects" ) and die "Could not change ownership of $_ for repo: $!";
-
+ chdir( "/srv/git" ); # so git-clone can do the work of resolving local repo names for us
if ( defined $source ) {
- $ENV{"GIT_DIR"} = $source;
- system( "/usr/bin/git", "push", "--mirror", $repo->path ) and die "Could not push refs to new repository!";
- delete $ENV{"GIT_DIR"};
+ system( "/bin/chown", $user . "." . $user, $repo->path ) and die "Could not change ownership of repo path!"; # permissions are overridden later
+ if ( system( "/usr/bin/sudo", "-u", $user, "/usr/bin/git", "clone", "--bare", "--no-hardlinks", "--quiet", $source, $repo->path ) ) { # sudo -u $user needed in order to test user readability of whatever they want to clone. the mode o+rx should probably be masked off if we want private repos to stay private.
+ system( "/bin/rm", "-r", $repo->path ) and die "Failed to clean up after failed clone operation!";
+ die( "Could not clone repository!\n" );
+ };
+ } else {
+ system( "/usr/bin/git", "init", "--bare", "--quiet", $repo->path ) and die "Could not initialize git repo!";
};
+ system( "/bin/chown", "-R", $user->name, $repo->path . "/objects" ) and die "Could not change ownership of $_ for repo: $!";
+
$repo->description( $description );
$repo->rebuild_git;
@@ -544,7 +599,17 @@ sub _build_globally_writable {
sub _build_cgit_url {
my ( $s ) = @_;
- return $s->config->piny_ikiwikisecureurl . "cgit/" . $s->name;
+ if ( $s->config->core_sharedrepository eq "0666" ) {
+ return $s->config->piny_ikiwikisecureurl . "cgit/" . $s->name;
+ } elsif ( $s->config->core_sharedrepository =~ /^(0664|all|everybody|world)$/ ) {
+ return $s->config->piny_ikiwikisecureurl . "cgit/" . $s->name;
+ } elsif ( $s->config->core_sharedrepository =~ /^(0660|true|1|group)$/ ) {
+ return $s->config->piny_ikiwikisecureurl . "auth/cgit/" . $s->name;
+ } elsif ( $s->config->core_sharedrepository =~ /^(0640|false|0)$/ ) {
+ return $s->config->piny_ikiwikisecureurl . "auth/cgit/" . $s->name;
+ } else {
+ die ( $s->config->core_sharedrepository . "is an unhandled value!" );
+ };
}
sub _build_ikiwiki_setup {
@@ -593,7 +658,17 @@ sub _build_ikiwiki_setup {
sub _build_ikiwiki_destdir {
my ( $s ) = @_;
- return $s->config->piny_ikiwikidestdir . $s->name;
+ if ( $s->config->core_sharedrepository eq "0666" ) {
+ return ( $s->config->piny_ikiwikidestdir . $s->name );
+ } elsif ( $s->config->core_sharedrepository =~ /^(0664|all|everybody|world)$/ ) {
+ return ( $s->config->piny_ikiwikidestdir . $s->name );
+ } elsif ( $s->config->core_sharedrepository =~ /^(0660|true|1|group)$/ ) {
+ return ( $s->config->piny_ikiwikisecurepath . "read/" . $s->name );
+ } elsif ( $s->config->core_sharedrepository =~ /^(0640|false|0)$/ ) {
+ return ( $s->config->piny_ikiwikisecurepath . "read/" . $s->name );
+ } else {
+ die ( $s->config->core_sharedrepository . "is an unhandled value!" );
+ };
};
sub _build_ikiwiki_srcdir {
@@ -605,19 +680,29 @@ sub _build_ikiwiki_srcdir {
sub _build_ikiwiki_url {
my ( $s ) = @_;
- return $s->config->piny_ikiwikiurl . $s->name;
+ if ( $s->config->core_sharedrepository eq "0666" ) {
+ return ( $s->config->piny_ikiwikiurl . $s->name );
+ } elsif ( $s->config->core_sharedrepository =~ /^(0664|all|everybody|world)$/ ) {
+ return ( $s->config->piny_ikiwikiurl . $s->name );
+ } elsif ( $s->config->core_sharedrepository =~ /^(0660|true|1|group)$/ ) {
+ return ( $s->config->piny_ikiwikisecureurl . "read/" . $s->name );
+ } elsif ( $s->config->core_sharedrepository =~ /^(0640|false|0)$/ ) {
+ return ( $s->config->piny_ikiwikisecureurl . "read/" . $s->name );
+ } else {
+ die ( $s->config->core_sharedrepository . "is an unhandled value!" );
+ };
};
sub _build_ikiwiki_cgiurl {
my ( $s ) = @_;
- return $s->config->piny_ikiwikisecureurl . "repos/" . $s->name . "/ikiwiki.cgi";
+ return $s->config->piny_ikiwikisecureurl . "write/" . $s->name . "/ikiwiki.cgi";
};
sub _build_secure_path {
my ( $s ) = @_;
- return $s->config->piny_ikiwikisecurepath . "repos/" . $s->name;
+ return $s->config->piny_ikiwikisecurepath . "write/" . $s->name;
};
sub _build_ikiwiki_cgipath {
@@ -629,27 +714,71 @@ sub _build_ikiwiki_cgipath {
sub _build_ikiwiki_historyurl {
my ( $s ) = @_;
- if ( defined $s->config->{"https_url"} ) {
- return $s->config->{"https_url"} . "cgit/" . $s->name . "/log/[[file]]";
+ return $s->cgit_url . "/log/[[file]]";
+};
+
+sub _build_ikiwiki_diffurl {
+ my ( $s ) = @_;
+
+ return $s->cgit_url . "/log/[[file]]";
+};
+
+sub _build_apache_global_config {
+ my ( $s ) = @_;
+
+ if ( $s->config->core_sharedrepository eq "0666" ) {
+ return (
+ "<Directory " . $s->secure_path . ">\n SSLRequireSSL\n AuthPAM_Enabled on\n" . " AuthPAM_FallThrough off\n AuthBasicAuthoritative off\n AuthType Basic\n AuthName \"Valid Piny user needed.\"\n" . " Require valid-user\n" . " </Directory>\n"
+ );
+ } elsif ( $s->config->core_sharedrepository =~ /^(0664|all|everybody|world)$/ ) {
+ return (
+ "<Directory " . $s->secure_path . ">\n SSLRequireSSL\n AuthPAM_Enabled on\n AuthGROUP_Enabled on\n AuthPAM_FallThrough off\n AuthBasicAuthoritative off\n AuthType Basic\n AuthName \"User with access to " . $s->name . " repository needed.\"\n Require group " . $s->group->name . "\n</Directory>\n"
+ );
+ } elsif ( $s->config->core_sharedrepository =~ /^(0660|true|1|group)$/ ) {
+ return (
+ "<Directory " . $s->secure_path . ">\n SSLRequireSSL\n AuthPAM_Enabled on\n AuthGROUP_Enabled on\n AuthPAM_FallThrough off\n AuthBasicAuthoritative off\n AuthType Basic\n AuthName \"User with access to " . $s->name . " repository needed.\"\n Require group " . $s->group->name . "\n</Directory>\n" .
+ "<Directory " . $s->ikiwiki_destdir . ">\n SSLRequireSSL\n AuthPAM_Enabled on\n AuthGROUP_Enabled on\n AuthPAM_FallThrough off\n AuthBasicAuthoritative off\n AuthType Basic\n AuthName \"User with access to " . $s->name . " repository needed.\"\n Require group " . $s->group->name . "\n</Directory>\n"
+ );
+ } elsif ( $s->config->core_sharedrepository =~ /^(0640|false|0)$/ ) {
+ return (
+ "<Directory " . $s->secure_path . ">\n SSLRequireSSL\n AuthPAM_Enabled on\n" . " AuthPAM_FallThrough off\n AuthBasicAuthoritative off\n AuthType Basic\n AuthName \"Owner of " . $s->name . " repository needed.\"\n Require user " . $s->owner->name . "\n</Directory>\n" .
+ "<Directory " . $s->ikiwiki_destdir . ">\n SSLRequireSSL\n AuthPAM_Enabled on\n AuthGROUP_Enabled on\n AuthPAM_FallThrough off\n AuthBasicAuthoritative off\n AuthType Basic\n AuthName \"User with access to " . $s->name . " repository needed.\"\n Require group " . $s->group->name . "\n</Directory>\n"
+ );
} else {
- return $s->config->piny_ikiwikisecureurl . "cgit/" . $s->name . "/log/[[file]]";
+ die ( $s->config->core_sharedrepository . "is an unhandled value!" );
};
};
-sub _build_ikiwiki_diffurl {
+sub _build_apache_secure_config {
my ( $s ) = @_;
- if ( defined $s->config->{"https_url"} ) {
- return $s->config->{"https_url"} . "cgit/" . $s->name . "/diff/?id=[[sha1_commit]]";
+ if ( $s->config->core_sharedrepository eq "0666" ) {
+ return ( "Redirect /read/" . $s->name . " " . $s->ikiwiki_url . "\n" );
+ } elsif ( $s->config->core_sharedrepository =~ /^(0664|all|everybody|world)$/ ) {
+ return ( "Redirect /read/" . $s->name . " " . $s->ikiwiki_url . "\n" );
+ } elsif ( $s->config->core_sharedrepository =~ /^(0660|true|1|group)$/ ) {
+ return ( "Redirect /cgit/" . $s->name . " /auth/cgit/" . $s->name . "\n" );
+ } elsif ( $s->config->core_sharedrepository =~ /^(0640|false|0)$/ ) {
+ return ( "Redirect /cgit/" . $s->name . " /auth/cgit/" . $s->name . "\n" );
} else {
- return $s->config->piny_ikiwikisecureurl . "cgit/" . $s->name . "/diff/?id=[[sha1_commit]]";
+ die ( $s->config->core_sharedrepository . "is an unhandled value!" );
};
};
-sub _build_apache_config {
+sub _build_apache_www_config {
my ( $s ) = @_;
- return "<Directory " . $s->secure_path . ">\n AuthPAM_Enabled on\n AuthGROUP_Enabled on\n AuthPAM_FallThrough off\n AuthBasicAuthoritative off\n AuthType Basic\n AuthName \"User access to " . $s->name . " repository needed.\"\n Require group " . $s->group->name . "\n</Directory>\n";
+ if ( $s->config->core_sharedrepository eq "0666" ) {
+ return ( "\n" );
+ } elsif ( $s->config->core_sharedrepository =~ /^(0664|all|everybody|world)$/ ) {
+ return ( "\n" );
+ } elsif ( $s->config->core_sharedrepository =~ /^(0660|true|1|group)$/ ) {
+ return ( "Redirect /" . $s->name . " " . $s->ikiwiki_url . "\n" );
+ } elsif ( $s->config->core_sharedrepository =~ /^(0640|false|0)$/ ) {
+ return ( "Redirect /" . $s->name . " " . $s->ikiwiki_url . "\n" );
+ } else {
+ die ( $s->config->core_sharedrepository . "is an unhandled value!" );
+ };
};
sub _build_config {