Fix permissions/ownership for push-hosted projects
[girocco.git] / cgi / regproj.cgi
blob2a48fc6fed5026a97039b58ab5cbd3af57e6ddd4
1 #!/usr/bin/perl
2 # (c) Petr Baudis <pasky@suse.cz>
3 # GPLv2
5 use strict;
6 use warnings;
7 use CGI qw(:standard :escapeHTML -nosticky);
8 use CGI::Util qw(unescape);
9 use CGI::Carp qw(fatalsToBrowser);
11 my $cgi = CGI->new;
13 print $cgi->header(-type=>'text/html', -charset => 'utf-8');
15 print "<html><head><title>Git Project Registration</title></head>\n";
16 print "<body><h1>Register Project</h1></body>\n";
18 sub scrypt {
19 my ($pwd) = @_;
20 crypt($pwd, join ('', ('.', '/', 2..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64]));
23 sub save_proj_data {
24 my ($path, $url, $email, $desc) = @_;
25 open F, ">$path/base_url" or die "base_url failed: $!"; print F "$url\n"; close F;
26 open F, ">$path/owner" or die "owner failed: $!"; print F "$email\n"; close F;
27 open F, ">$path/description" or die "desc failed: $!"; print F "$desc\n"; close F;
30 sub add_group {
31 my ($name, $pwd, $xtra) = @_;
32 my $gid = 65536;
33 # racy!
34 open F, "/home/repo/j/etc/group" or die "group failed: $!";
35 while (<F>) {
36 my $agid = (split /:/)[2];
37 $gid = $agid + 1 if ($agid >= $gid);
39 close F;
40 open F, ">>/home/repo/j/etc/group" or die "group append failed: $!";
41 print F "$name:".scrypt($pwd).":$gid:$xtra\n";
42 close F;
43 $gid;
46 sub setup_push {
47 my ($name, $pwd, $email, $url, $desc) = @_;
48 system("cg-admin-setuprepo -g repo /srv/git/$name.git") == 0 or die "cg-admin-setuprepo failed: $?";
49 open X, ">/srv/git/$name.git/.nofetch" or die "nofetch failed: $!"; close X;
50 save_proj_data("/srv/git/$name.git", $url, $email, $desc);
51 chmod 0664, map { "/srv/git/$name.git/$_" } qw(base_url owner description);
52 add_group($name, $pwd, '');
53 print "<p>";
54 print "Project successfuly set up. ";
55 print "You can <a href=\"p/editproj.pl\">assign users</a> now (use project name as username, admin password as password). ";
56 print "You need to <a href=\"reguser.pl\">register a user</a> first if you have not done so yet. ";
57 print "(One user can have push access to multiple projects and multiple users can have push access to one project.)";
58 print "</p>\n";
59 print "<p>You may experience permission problems if you try to push right now. If so, that should get fixed automagically in few minutes.</p>\n";
60 print "<p>Enjoy yourself!</p>\n";
61 print "</body></html>\n";
64 sub setup_mirror {
65 my ($name, $pwd, $email, $url, $desc) = @_;
66 mkdir "/home/repo/repodata/to-clone/$name" or die "mkdir failed: $!";
67 save_proj_data("/home/repo/repodata/to-clone/$name", $url, $email, $desc);
68 chmod 0775, "/home/repo/repodata/to-clone/$name" or die "chmod failed: $!";
69 add_group($name, $pwd, ':');
70 print "<p>Initiated mirroring. You will be notified by mail about results.</p>\n";
71 print "</body></html>\n";
74 if ($cgi->param('name')) {
75 # submitted, let's see
76 # FIXME: racy, do a lock
77 my $err = 0;
78 sub err { print "<p style=\"text-color: red\">@_</p>\n"; $err++; }
79 my $name = $cgi->param('name'); $name =~ s/^\s*(.*?)\s*$/$1/;
80 my $desc = $cgi->param('desc'); $desc =~ s/^\s*(.*?)\s*$/$1/;
81 my $email = $cgi->param('email'); $email =~ s/^\s*(.*?)\s*$/$1/;
82 my $url = $cgi->param('url'); $url =~ s/^\s*(.*?)\s*$/$1/;
83 my $pwd = $cgi->param('pwd');
84 $name =~ /^[a-zA-Z0-9_+-]+$/
85 or err "Name contains invalid characters.";
86 (-d "/srv/git/$name.git" or -d "/home/repo/repodata/cloning/$name" or -d "/home/repo/repodata/to-clone/$name")
87 and err "Project with that name already exists.";
88 if ($url) {
89 $url =~ /^http:\/\/[a-zA-Z0-9-.]+\/[_\%a-zA-Z0-9.\/~-]+$/ or
90 $url =~ /^git:\/\/[a-zA-Z0-9-.]+\/[_\%a-zA-Z0-9.\/~-]+$/
91 or err "Invalid URL. Note that only HTTP and Git protocol is supported. If the URL contains funny characters, contact me.";
92 } else {
93 $cgi->param('mode') eq 'mirror'
94 and err "Missing URL.";
96 $email =~ /^[a-zA-Z0-9+._-]+@[a-zA-Z0-9-.]+$/
97 or err "Your email sure looks weird...?";
98 length($desc) <= 1024
99 or err "<b>Short</b> description length > 1kb!";
100 if ($err) {
101 print "<p>Registration aborted due to $err errors.</p>\n";
102 } else {
103 if ($cgi->param('mode') eq 'mirror') {
104 setup_mirror($name, $pwd, $email, $url, $desc);
105 } elsif ($cgi->param('mode') eq 'push') {
106 setup_push($name, $pwd, $email, $url, $desc);
108 exit;
112 print "<p>Here you can register a project. It can be hosted in two modes: mirror mode and push mode. In the first mode, we will check another repository at a given URL each hour and mirror any new updates. In the second mode, registered users with appropriate permissions will be able to push to the repository. You currently cannot switch freely between those two modes; if you want to switch an existing project, please contact the administrator.</p>\n";
113 print "<p>You will need the admin password to adjust project settings later (mirroring URL, list of users allowed to push, project description, ...). Use the project name as the username when asked by the browser.</p>\n";
114 print "<p>By submitting this form, you are confirming that the repository contains only free software and redistributing it does not violate any law of Czech Republic. Have fun!</p>\n";
115 print "<form method=\"post\">\n";
116 print "<p>Project name (w/o the .git suffix): <input type=\"text\" name=\"name\" /></p>\n";
117 print "<p>Admin password: <input type=\"password\" name=\"pwd\" /></p>\n";
118 print "<p>E-mail contact: <input type=\"text\" name=\"email\" /></p>\n";
119 print "<p>Description: <input type=\"text\" name=\"desc\" /></p>\n";
120 print "<p>Hosting mode:</p><ul>\n";
121 print "<li><input type=\"radio\" name=\"mode\" value=\"mirror\" />Mirror mode. Repository URL: <input type=\"text\" name=\"url\" /></li>\n";
122 print "<li><input type=\"radio\" name=\"mode\" value=\"push\" />Push mode.</li></ul>\n";
123 print "<p><input type=\"submit\" name=\"y0\" value=\"Register\" /></p>\n";
124 print "</form>\n";
125 print "</body></html>\n";