summaryrefslogtreecommitdiffstats
path: root/scripts/credstore.pl
blob: f6ad95bfcb1291ef7d8a66568a955f9a85e2e1a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
#store fingerprints of know users so can verify
#/credstore
use Irssi;
use warnings;
use strict;
use vars qw($VERSION %IRSSI $DBFILE $DEBUG $OPT $FING);

$VERSION = "1.3";
%IRSSI = (
    authors     => "Benedetto",
    contact     => "dettox\@gmail.com",
    name        => "credstore",
    description => "store fingerprints of know users so can verify",
    license     => "GPLv3+",
    url         => "http://irssi.org/",
    changed	=> "Thu Jan 20 13:07:49 GMT 2014",
);

$DBFILE = Irssi::get_irssi_dir() . "/credstore.txt";
$OPT = "help";
$FING = "";

sub show_help() {
	my $help="CREDSTORE $VERSION
/CREDSTORE add <nickname> [add nickname fingerprint]
/CREDSTORE del <nickname> [del nickname fingerprint]
/CREDSTORE verify <nickname> [verify nickname fingerprint]
/CREDSTORE [display this help]
";
	Irssi::print("$help",MSGLEVEL_CLIENTCRAP);
}

sub redir_init {
    # set up event to handler mappings
    Irssi::signal_add
    ({
    	'redir credstore_whois_user'       => 'event_whois_user',
    	'redir credstore_whois_server'       => 'event_whois_server',
	'redir credstore_whois_end'        => 'event_whois_end',
	'redir credstore_whois_nosuchnick' => 'event_whois_nosuchnick',
	'redir credstore_whois_timeout'    => 'event_whois_timeout',
	'redir credstore_whois_various'    => 'event_whois_various',
	'redir credstore_whois_idle'    => 'event_whois_idle',
	'redir credstore_whois_channels'    => 'event_whois_channels',
	'redir credstore_whois_modes'    => 'event_whois_modes',
	'redir credstore_whois_usermode'    => 'event_whois_usermode',
	'redir credstore_whois_usermode326'    => 'event_whois_usermode326',
	'redir credstore_whois_realhost'    => 'event_whois_realhost',
	'redir credstore_whois_realhost327'    => 'event_whois_realhost327',
	'redir credstore_whois_realhost338'    => 'event_whois_realhost338',
	});
}

sub request_whois {
    my ($server, $nick) = @_;
        $server->redirect_event
	(
		'whois', 1, $nick, 0,             # command, remote, arg, timeout
	        'redir credstore_whois_timeout', # error handler
	        {
	        'event 311' => 'redir credstore_whois_user', # event mappings
	        'event 312' => 'redir credstore_whois_server',
	        'event 317' => 'redir credstore_whois_idle',
	        'event 318' => 'redir credstore_whois_end',
	        'event 319' => 'redir credstore_whois_channels',
	        'event 327' => 'redir credstore_whois_realhost327',
	        'event 338' => 'redir credstore_whois_realhost338',
	        'event 378' => 'redir credstore_whois_realhost',
	        'event 326' => 'redir credstore_whois_usermode326',
	        'event 377' => 'redir credstore_whois_usermode',
	        'event 379' => 'redir credstore_whois_modes',
		'event 401' => 'redir credstore_whois_nosuchnick',
		'event 275' => 'redir credstore_whois_various',
		'event 276' => 'redir credstore_whois_various',
		'event 671' => 'redir credstore_whois_various',
	        ''          => 'event empty',
	        }
        );

	Irssi::print("CREDSTORE Sending Command: WHOIS $nick", MSGLEVEL_CLIENTCRAP);
        $server->send_raw("whois $nick");
}

sub event_whois_user {
	my ($num, $nick, $user, $host, $empty, $realname) = ( split / +/, $_[1], 6 );
	Irssi::print("CREDSTORE WHOIS: $nick!$user\@$host $empty $realname", MSGLEVEL_CLIENTCRAP);
}

sub event_whois_various {
	my $data = $_[1];
	my $fingerp = get_fingerprint($data);
	if ( defined $fingerp && $fingerp ne "" ) {
		$FING = $data;
	}
    
	Irssi::print("CREDSTORE WHOIS: $data", MSGLEVEL_CLIENTCRAP);
}

sub event_whois_server {
	my ($empty, $nick, $whoserver, $desc) = ( split / +/, $_[1], 4 );
	Irssi::print("CREDSTORE WHOIS: $whoserver $desc", MSGLEVEL_CLIENTCRAP);
}

sub event_whois_idle {
	my ($empty, $nick, $sec, $signon, $rest) = ( split / +/, $_[1], 5 );
	my $days = int($sec/3600/24);
	my $hours = int(($sec%(3600*24))/3600);
	my $min = int(($sec%3600)/60);
	my $secs = int($sec%60);
	my $logint = gmtime($signon);
	Irssi::print("CREDSTORE WHOIS: $days days $hours hours $min mins $secs secs [signon: $logint]", MSGLEVEL_CLIENTCRAP);
}

sub event_whois_channels {
	my ($empty, $nick, $chans) = ( split / +/, $_[1], 3 );
	Irssi::print("CREDSTORE WHOIS: $chans", MSGLEVEL_CLIENTCRAP);
}

sub event_whois_realhost {
	my ($empty, $nick, $txt_real, $txt_hostname, $hostname) = ( split / +/, $_[1], 5 );
	Irssi::print("CREDSTORE WHOIS: $txt_real $txt_hostname $hostname", MSGLEVEL_CLIENTCRAP);
}

sub event_whois_realhost327 {
	my ($empty, $nick, $hostname, $ip, $text) = ( split / +/, $_[1], 5 );
	Irssi::print("CREDSTORE WHOIS: $hostname $ip $text", MSGLEVEL_CLIENTCRAP);
}

sub event_whois_realhost338 {
	my ($empty, $nick, $arg1, $arg2, $arg3) = ( split / +/, $_[1], 5 );
	if ( defined $arg1 && defined $arg2 ) {
		Irssi::print("CREDSTORE WHOIS: $nick $arg1 $arg2", MSGLEVEL_CLIENTCRAP);
	} elsif ( defined $arg2 && defined $arg3 ) {
		Irssi::print("CREDSTORE WHOIS: $nick $arg1 $arg2", MSGLEVEL_CLIENTCRAP);
	}
}

sub event_whois_usermode {
	my ($empty, $txt_user, $nick, $usermode) = ( split / +/, $_[1], 4 );
	Irssi::print("CREDSTORE WHOIS: $txt_user $usermode", MSGLEVEL_CLIENTCRAP);
}

sub event_whois_usermode326 {
	my ($empty, $nick, $usermode) = ( split / +/, $_[1], 3 );
	Irssi::print("CREDSTORE WHOIS: $usermode", MSGLEVEL_CLIENTCRAP);
}

sub event_whois_modes {
	my ($empty, $nick, $modes) = ( split / +/, $_[1], 3 );
	Irssi::print("CREDSTORE WHOIS: $modes", MSGLEVEL_CLIENTCRAP);
}

sub event_whois_end {
	my ($server, $data) = @_;
	my ($nick) = ( split / +/, $data, 3 )[1];
	my $fingerp = get_fingerprint($FING);

	if ( $OPT eq 'add' ) {
		if ( defined $fingerp && $fingerp ne "" ) {
			add_to_db($nick,$fingerp);
		} else { 
			Irssi::print("CREDSTORE Error: No Whois Fingerprint for $nick",MSGLEVEL_CLIENTCRAP);
		}
	} elsif ( $OPT eq 'verify' ) {
			my $fingerp2 = read_from_db($nick);
			if ( defined $fingerp && $fingerp ne "" ) {
				if ( lc($fingerp) ne lc($fingerp2) ) {
					Irssi::print("CREDSTORE Error: Differents Fingerprints for $nick",MSGLEVEL_CLIENTCRAP);
					Irssi::print("CREDSTORE  DB:$fingerp2\nCREDSTORE NEW:$fingerp",MSGLEVEL_CLIENTCRAP);
				} else { 
					Irssi::print("CREDSTORE $nick Fingerprint is OK",MSGLEVEL_CLIENTCRAP);
				}
			} else { 
				Irssi::print("CREDSTORE Error: No Whois Fingerprint for $nick",MSGLEVEL_CLIENTCRAP);
			}
	}
}

sub event_whois_nosuchnick {
    my ($server, $data) = @_;
    my $nick = ( split / +/, $data, 4)[1];
    Irssi::active_win->print("CREDSTORE WHOIS Error: no such nick $nick - aborting.",MSGLEVEL_CLIENTCRAP);
}

sub event_whois_timeout {
    my ($server, $data) = @_;
    Irssi::print("CREDSTORE WHOIS whois_timeout", MSGLEVEL_CLIENTCRAP);
}

sub dbfile_check {
	if ( ! -w $DBFILE ) {
		open FH,">",$DBFILE or croak $!;
		print FH "";
		if(!close(FH)) {
			Irssi::print("CREDSTORE Error on $DBFILE",MSGLEVEL_CLIENTCRAP);
		}
	}
}

#add nick,fingerprint to DB
sub add_to_db {
	my ($nick,$fingerp) = @_;
	if ( -w $DBFILE ) {
		open FH,">>",$DBFILE or croak $!;
		print FH "$nick\t$fingerp\n";
		if(!close(FH)) {
			Irssi::print("CREDSTORE Error on $DBFILE",MSGLEVEL_CLIENTCRAP);
		}
		Irssi::print("CREDSTORE $nick($fingerp)",MSGLEVEL_CLIENTCRAP);
	} else {
		Irssi::print("CREDSTORE Error on $DBFILE",MSGLEVEL_CLIENTCRAP);
	}
}

#del nick,fingerprint from DB
sub del_from_db {
	my ($nick) = @_;
	my $nick2; my $fingerp;
	my $filetmp = "$DBFILE.tmp";
	if ( -w $DBFILE && ! -w $filetmp ) {
		open FHR,"<",$DBFILE or croak $!;
		open FHW,">",$filetmp or croak $!;
		while (<FHR>) {
			my @line = split(/\t/, $_);
			($nick2,$fingerp) = @line;
			if ( $nick ne $nick2 ) {
				print FHW "$nick2\t$fingerp";
			}
		}
		if(!close(FHR)) {
			Irssi::print("CREDSTORE Error on $DBFILE",MSGLEVEL_CLIENTCRAP);
		}
		if(!close(FHW)) {
			Irssi::print("CREDSTORE Error on $DBFILE",MSGLEVEL_CLIENTCRAP);
		}
		unlink($DBFILE);
		rename($filetmp,$DBFILE);
		Irssi::print("CREDSTORE $nick removed from DB",MSGLEVEL_CLIENTCRAP);
	} else {
		Irssi::print("CREDSTORE Error on $DBFILE",MSGLEVEL_CLIENTCRAP);
	}
}

#read nick,fingerprint from DB
sub read_from_db {
	my ($nick) = @_;
	my $nick2; my $fingerp;
	
	if ( -w $DBFILE ) {
		open FH,"<",$DBFILE or croak $!;
		while (<FH>) {
			my @line = split(/\t/, $_);
			($nick2,$fingerp) = @line;
			if ( defined $DEBUG ) {
				Irssi::print("$nick2  ...  $fingerp\n",MSGLEVEL_CLIENTCRAP);
			}
			if ( $nick eq $nick2 ) {
				$_ = $fingerp;
				$fingerp =~ s/\n//g;
				return $fingerp;
			} else {
				$fingerp = "";
			}
		}
		if(!close(FH)) {
			Irssi::print("CREDSTORE Error on $DBFILE",MSGLEVEL_CLIENTCRAP);
		}
	} else {
		Irssi::print("CREDSTORE Error on $DBFILE",MSGLEVEL_CLIENTCRAP);
	}
	return $fingerp;
}

#get fingerprint from input
sub get_fingerprint {
	my ($output) = @_;
	my $fingerp;

	$_ = $output;
	while ( $output =~ s/.*\s(\w{40}).*/$1/ ) {
		$fingerp = $1;
	}
	return $fingerp;
}

#add fingerprint for nick
sub add_nickname {
	my ($nick,$server) = @_;
	my $exfingerp = read_from_db($nick);
	if ( defined $exfingerp && $exfingerp ne "" ) {
		Irssi::print("CREDSTORE Error: $nick just Exist",MSGLEVEL_CLIENTCRAP);
		return;
	}
	Irssi::print("CREDSTORE Adding $nick ... ",MSGLEVEL_CLIENTCRAP);
	request_whois($server,$nick);
}

#del nick from db
sub del_nickname {
	my ($nick) = @_;
	Irssi::print("CREDSTORE Deleting $nick ...",MSGLEVEL_CLIENTCRAP);
	del_from_db($nick);
}

#verify nick, fingerprint
sub verify_nickname {
	my ($nick,$server) = @_;
	Irssi::print("CREDSTORE Verify $nick ...",MSGLEVEL_CLIENTCRAP);

	my ($fingerp) = read_from_db($nick);
	if ( defined $fingerp && $fingerp ne "" ) {
		request_whois($server,$nick);
	} else { 
		Irssi::print("CREDSTORE Error: $nick not in DB",MSGLEVEL_CLIENTCRAP);
	}
}

sub cmd_credstore {
	my ($data, $server, $witem) = @_;
	my $cmd; my $nick; my $conn = 0;
	( $cmd, $nick ) = split(/ /, $data);
	
	if (!$server || !$server->{connected}) {
		$conn = 1;
		Irssi::print("CREDSTORE Warning: not connected",MSGLEVEL_CLIENTCRAP);
	}
	
	if ( defined $cmd && defined $nick) {
		$OPT = $cmd;
		if ($cmd eq 'add' && !$conn) {
			add_nickname($nick,$server);
		} elsif ($cmd eq 'del' && !$conn) {
			del_nickname($nick);
		} elsif ($cmd eq 'verify' && !$conn) {
			verify_nickname($nick,$server);
		} else {
			show_help();
		}
	} else {
		show_help();
	}
	return(0);
}
#signal handler
redir_init();
#DB file exist and is writable
dbfile_check();

Irssi::command_bind('credstore', 'cmd_credstore');