/[suikacvs]/test/suika-accounts/users.pl
Suika

Contents of /test/suika-accounts/users.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (hide annotations) (download)
Sat Nov 1 10:13:14 2008 UTC (16 years ago) by wakaba
Branch: MAIN
Changes since 1.3: +22 -0 lines
File MIME type: text/plain
Send a mail message when a significant change occurs

1 wakaba 1.1 use strict;
2    
3 wakaba 1.4 my $mail_from = q<webmaster@suika.fam.cx>;
4     my $mail_to = q<webmaster@suika.fam.cx>;
5     my $subject_prefix = q<[suika.fam.cx account]>;
6    
7 wakaba 1.1 my $user_data_dir_name = 'data/';
8     my $user_prop_file_suffix = '.user';
9    
10     my $group_data_dir_name = 'data/';
11     my $group_prop_file_suffix = '.group';
12    
13     my $htpasswd_file_name = 'data/htpasswd';
14     my $htgroup_file_name = 'data/htgroup';
15    
16     my $lock_file_name = $user_data_dir_name . '.lock';
17    
18     use Fcntl ':flock';
19     my $Lock;
20    
21     sub lock_start () {
22     return if $Lock;
23    
24     open $Lock, '>', $lock_file_name or die "$0: $lock_file_name: $!";
25     flock $Lock, LOCK_EX;
26     } # lock_start
27    
28     sub get_prop_hash ($) {
29     my $user_prop_file_name = shift;
30    
31     return undef unless -f $user_prop_file_name;
32    
33     my $r = {};
34    
35     open my $user_prop_file, '<:encoding(utf8)', $user_prop_file_name
36     or die "$0: $user_prop_file_name: $!";
37     while (<$user_prop_file>) {
38     tr/\x0D\x0A//d;
39     my ($n, $v) = split /:/, $_, 2;
40     if ($n =~ s/^\@//) {
41     push @{$r->{$n} ||= []}, $v // '';
42     } elsif ($n =~ s/^%//) {
43     $r->{$n}->{$v // ''} = 1;
44     } else {
45     $n =~ s/^\$//;
46     $r->{$n} = $v // '';
47     }
48     }
49    
50     return $r;
51     } # get_prop_hash
52    
53     sub set_prop_hash ($$) {
54     my $user_prop_file_name = shift;;
55     my $prop = shift;
56    
57     my $has_file = -f $user_prop_file_name;
58    
59     open my $user_prop_file, '>:encoding(utf8)', $user_prop_file_name
60     or die "$0: $user_prop_file_name: $!";
61     for my $prop_name (sort {$a cmp $b} keys %$prop) {
62     if (ref $prop->{$prop_name} eq 'ARRAY') {
63     my $v = '@' . $prop_name;
64     $v =~ tr/\x0D\x0A://d;
65     for (@{$prop->{$prop_name}}) {
66     my $pv = $_;
67     $pv =~ tr/\x0D\x0A/ /;
68     print $user_prop_file $v . ':' . $pv . "\x0A";
69     }
70     } elsif (ref $prop->{$prop_name} eq 'HASH') {
71     my $v = '%' . $prop_name;
72     $v =~ tr/\x0D\x0A://d;
73     for (sort {$a cmp $b} keys %{$prop->{$prop_name}}) {
74     next unless $prop->{$prop_name}->{$_};
75     my $pv = $_;
76     $pv =~ tr/\x0D\x0A/ /;
77     print $user_prop_file $v . ':' . $pv . "\x0A";
78     }
79     } else {
80     my $v = '$' . $prop_name;
81     $v =~ tr/\x0D\x0A://d;
82     my $pv = $prop->{$prop_name};
83     $pv =~ tr/\x0D\x0A/ /;
84     print $user_prop_file $v . ':' . $pv . "\x0A";
85     }
86     }
87     close $user_prop_file_name;
88    
89     system_ ('cvs', 'add', $user_prop_file_name) unless $has_file;
90     } # set_prop_hash
91    
92     sub commit ($) {
93     my $msg = shift // $0;
94     system_ ('cvs', 'commit', -m => $msg, $user_data_dir_name);
95     } # commit
96    
97     sub get_user_prop ($) {
98     my $user_id = shift;
99     return get_prop_hash ($user_data_dir_name . $user_id . $user_prop_file_suffix);
100     } # get_user_prop
101    
102     sub set_user_prop ($$) {
103     my ($user_id, $prop) = @_;
104     return set_prop_hash ($user_data_dir_name . $user_id . $user_prop_file_suffix,
105     $prop);
106     } # set_user_prop
107    
108     sub get_group_prop ($) {
109     my $group_id = shift;
110     return get_prop_hash ($group_data_dir_name .
111     $group_id . $group_prop_file_suffix);
112     } # get_group_prop
113    
114     sub set_group_prop ($$) {
115     my ($group_id, $prop) = @_;
116     return set_prop_hash ($group_data_dir_name .
117     $group_id . $group_prop_file_suffix,
118     $prop);
119     } # set_group_prop
120    
121     sub get_all_users () {
122     my @r;
123     opendir my $user_data_dir, $user_data_dir_name;
124     for (readdir $user_data_dir) {
125     if (/^([0-9a-z-]+)\Q$user_prop_file_suffix\E$/) {
126     push @r, $1;
127     }
128     }
129     return @r;
130     } # get_all_users
131    
132     sub get_all_groups () {
133     my @r;
134     opendir my $group_data_dir, $group_data_dir_name;
135     for (readdir $group_data_dir) {
136     if (/^([0-9a-z-]+)\Q$group_prop_file_suffix\E$/) {
137     push @r, $1;
138     }
139     }
140     return @r;
141     } # get_all_groups
142    
143     sub regenerate_htpasswd_and_htgroup () {
144     my %htpasswd;
145     my %htgroup;
146    
147     my @group = get_all_groups ();
148    
149     for my $user_id (get_all_users ()) {
150     my $user_prop = get_user_prop ($user_id);
151     next if $user_prop->{disabled};
152     next unless $user_prop->{pass_crypted};
153    
154     $htpasswd{$user_id} = $user_prop->{pass_crypted};
155    
156     for (@group) {
157     if ($user_prop->{'group.' . $_}->{member}) {
158     $htgroup{$_}->{$user_id} = 1;
159     }
160     }
161     }
162    
163     open my $file, '>', $htpasswd_file_name or die "$0: $htpasswd_file_name: $!";
164     for (sort {$a cmp $b} keys %htpasswd) {
165     print $file $_, ':', $htpasswd{$_}, "\x0A";
166     }
167    
168     open my $file, '>', $htgroup_file_name or die "$0: $htgroup_file_name: $!";
169     for my $group_id (sort {$a cmp $b} keys %htgroup) {
170     print $file $group_id, ': ',
171     join ' ', sort {$a cmp $b} keys %{$htgroup{$group_id}};
172     print $file "\x0A";
173     }
174     } # regenerate_htpasswd_and_htgroup
175    
176 wakaba 1.3 sub print_error ($$;$) {
177     my ($code, $text, $text_arg) = @_;
178     our $Lang;
179 wakaba 1.1 binmode STDOUT, ':encoding(utf-8)';
180 wakaba 1.3 my $_text = $text;
181     $_text =~ s/%s/$text_arg/g;
182     print qq[Status: $code $_text
183 wakaba 1.1 Content-Type: text/html; charset=utf-8
184    
185     <!DOCTYPE HTML>
186 wakaba 1.3 <html lang="$Lang">
187     <title lang=en>$code @{[htescape ($_text)]}</title>
188 wakaba 1.2 <link rel=stylesheet href="/www/style/html/xhtml">
189 wakaba 1.3 <h1>];
190     print_text ('Error');
191     print q[</h1><p>];
192     print_text ($text, sub { print '', htescape ($text_arg) });
193     print_text ('.');
194     print q[<!--];
195 wakaba 1.1 print 0 for 0..511; # for WinIE
196     print q[-->];
197     } # print_error
198    
199     sub check_password ($) {
200     my $cgi = shift;
201    
202     my $user_pass = $cgi->get_parameter ('user-pass');
203     my $user_pass2 = $cgi->get_parameter ('user-pass2');
204     if ($user_pass ne $user_pass2) {
205     print_error (400, 'Two passwords you input are different');
206     exit;
207     }
208    
209     if (4 > length $user_pass) {
210     print_error (400, 'Password must be longer than 3 characters');
211     exit;
212     }
213    
214     my $pass_crypted = crypt $user_pass,
215     join '', (0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64];
216     return $pass_crypted;
217     } # check_password
218 wakaba 1.4
219     sub send_mail ($$) {
220     require Net::SMTP;
221     require Encode;
222    
223     my $smtp = Net::SMTP->new ('localhost');
224     $smtp->mail ($mail_from);
225     $smtp->to ($mail_to);
226     ## NOTE: What's wrong with UTF-8 Subject? :-)
227     $smtp->data (Encode::encode ('utf-8', "From: <$mail_from>
228     To: <$mail_to>
229     Subject: $_[0]
230     Content-Type: text/plain; charset=utf-8
231     MIME-Version: 1.0
232    
233     $_[1]"));
234     $smtp->send;
235     } # send_mail
236 wakaba 1.1
237     sub system_ (@) {
238     (system join (' ', map {quotemeta $_} @_) . " > /dev/null") == 0
239     or die "$0: $?";
240     } # system_
241    
242     sub htescape ($) {
243     my $s = shift;
244     $s =~ s/&/&amp;/g;
245     $s =~ s/</&lt;/g;
246     $s =~ s/>/&gt;/g;
247     $s =~ s/"/&quot;/g;
248     return $s;
249     } # htescape
250    
251     1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24