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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.6 - (show annotations) (download)
Sat May 15 03:29:27 2010 UTC (13 years, 11 months ago) by wakaba
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +1 -1 lines
File MIME type: text/plain
typo (9 Nov 2008 04:07:17)

1 use strict;
2
3 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 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;
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 sub print_error ($$;$) {
177 my ($code, $text, $text_arg) = @_;
178 our $Lang;
179 binmode STDOUT, ':encoding(utf-8)';
180 my $_text = $text;
181 $_text =~ s/%s/$text_arg/g;
182 print qq[Status: $code $_text
183 Content-Type: text/html; charset=utf-8
184
185 <!DOCTYPE HTML>
186 <html lang="$Lang" class=account-error>
187 <title lang=en>$code @{[htescape ($_text)]}</title>
188 <link rel=stylesheet href="/admin/style/common">
189 <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 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
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
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