-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathautoresponder.pl
executable file
·141 lines (130 loc) · 4.01 KB
/
autoresponder.pl
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
#!/usr/bin/perl
use strict; use warnings;
use Data::Dumper;
use Extism ':all';
use JSON::PP qw(decode_json);
use XTP;
# load XTP configuration
my $appid = $ENV{XTP_APPID};
my $token = $ENV{XTP_TOKEN};
# parse the incoming email
my %email = parse_incoming_email(@ARGV);
my $sender = $email{sender};
my $receiver = $email{receiver};
# if the receiver is root, check if it's a guest signup email
# if so reply with an invite link
if ($receiver eq 'root@localhost') {
my $subject = exists $email{headers}{Subject} ? $email{headers}{Subject} : '';
if ($subject =~ m!^/hackablee?mail\s+signup!) {
eval {
my $client = XTP::Client->new({
token => $token,
appId => $appid,
});
my $invite = $client->inviteGuest({
guestKey => email_to_guestKey($sender),
deliveryMethod => 'link'
});
my %email = (
headers => {
Subject => 'Hackable Email Invite',
To => $sender,
From => $receiver,
},
body => $invite->{link}
);
exit send_email($sender, $receiver, \%email);
};
if ($@) {
exit 70; # EX_SOFTWARE
}
}
}
# try to get a plugin
my $plugin = eval {
# Initialize the host functions
my $deliver = Extism::Function->new("deliver", [Extism_String], [Extism_String], sub {
my ($input) = @_;
my $email = decode_json($input);
my $rc = send_email($sender, $receiver, $email);
return JSON::PP::->new->utf8->allow_nonref->encode($rc);
});
my $reply = Extism::Function->new("reply", [Extism_String], [Extism_String], sub {
my ($input) = @_;
my $email = decode_json($input);
$email->{headers} = {
Subject => $email->{subject} // '',
To => $sender,
From => $receiver,
};
my $rc = send_email($sender, $receiver, $email);
return JSON::PP::->new->utf8->allow_nonref->encode($rc);
});
# Initialize an XTP client
my $client = XTP::Client->new({
token => $token,
appId => $appid,
extism => {functions => [$deliver, $reply], wasi => 1}
});
# Finally actually try to get a plugin
$client->getPlugin('on email', email_to_guestKey($receiver));
};
if ($@) {
# no plugin, or initializing XTP failed, let the email pass through
exit send_email($sender, $receiver, \%email);
}
# Call the guest's plugin
my $rc = eval {
my $res = $plugin->call('onEmail', \%email);
JSON::PP::->new->utf8->allow_nonref->decode($res)
};
if ($@) {
# Bounce, the plugin crashed
exit 70; # EX_SOFTWARE
}
# return the plugin's exit code
exit $rc;
sub email_to_guestKey {
my ($address) = @_;
unpack('H*', $address)
}
sub parse_incoming_email {
my ($sender, $receiver) = @_;
my %email = (sender => $sender, receiver => $receiver);
# parse headers
my $prevheader;
while(my $line = <STDIN>) {
if ($line eq "\n") {
last;
}
if ($line =~ /^\s/ && $prevheader) {
chomp $line;
$email{headers}{$prevheader} .= "\n$line";
next;
}
my ($header, $value) = $line =~ /^([^:]+):\s+(.+)$/ or die "failed to parse header line: '$line' ";
$email{headers}{$header} = $value;
$prevheader = $header;
}
# parse body (only text supported currently)
my $body = '';
while(my $line = <STDIN>) {
$body .= $line;
}
$email{body} = $body;
%email
}
sub send_email {
my ($sender, $receiver, $email) = @_;
open(my $chld, '|-', '/usr/sbin/sendmail', '-i', '-f', $sender, $receiver) // die "failed to open sendmail";
while (my ($header, $value) = each(%{$email->{headers}})) {
my $headerline = "$header: $value\n";
print $chld $headerline;
}
print $chld "\n";
print $chld $email->{body};
close($chld);
my $fullcode = $?;
my $code = $fullcode >> 8;
$code
}