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
|
package com.juick.server.api;
import com.juick.User;
import com.juick.server.CommandsManager;
import com.juick.server.EmailManager;
import com.juick.server.util.HttpForbiddenException;
import com.juick.server.util.UserUtils;
import com.juick.service.EmailService;
import com.juick.service.UserService;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.mail.util.MimeMessageParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import springfox.documentation.annotations.ApiIgnore;
import javax.inject.Inject;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.*;
@Controller
public class Service {
private static Logger logger = LoggerFactory.getLogger(Post.class);
@Inject
private UserService userService;
@Inject
private EmailService emailService;
@Inject
private CommandsManager commandsManager;
@Inject
private EmailManager emailManager;
@Value("${api_user:juick}")
private String serviceUser;
@Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
private String tmpDir;
@Value("${banned_emails:}")
private String[] ignoredEmails;
Session session = Session.getDefaultInstance(new Properties());
@ApiIgnore
@PostMapping("/api/mail")
@ResponseStatus(value = HttpStatus.OK)
public void processMail(InputStream data) throws Exception {
if (UserUtils.getCurrentUser().getName().equals(serviceUser)) {
MimeMessage msg = new MimeMessage(session, data);
logger.info("got msg {}", msg.toString());
String from = msg.getFrom() == null || msg.getFrom().length > 1 ? ((InternetAddress) msg.getSender()).getAddress()
: ((InternetAddress) msg.getFrom()[0]).getAddress();
User visitor = userService.getUserByEmail(from);
if (!visitor.isAnonymous()) {
MimeMessageParser parser = new MimeMessageParser(msg);
parser.parse();
final String[] body = {parser.getPlainContent()};
if (body[0] == null) {
parser.getAttachmentList().stream()
.filter(a -> a.getContentType().equals("text/plain")).findFirst()
.ifPresent(a -> {
try {
body[0] = IOUtils.toString(a.getInputStream(), StandardCharsets.UTF_8);
logger.info("got text: {}", body[0]);
} catch (IOException e) {
logger.info("attachment error: {}", e);
}
});
}
final String[] attachmentFName = new String[1];
parser.getAttachmentList().stream().filter(a ->
a.getContentType().equals("image/jpeg") || a.getContentType().equals("image/png"))
.findFirst().ifPresent(a -> {
logger.info("got attachment: {}", a.getContentType());
String attachmentType;
if (a.getContentType().equals("image/jpeg")) {
attachmentType = "jpg";
} else {
attachmentType = "png";
}
attachmentFName[0] = DigestUtils.md5Hex(UUID.randomUUID().toString()) + "." + attachmentType;
try {
logger.info("got inputstream: {}", a.getInputStream());
FileOutputStream fos = new FileOutputStream(Paths.get(tmpDir, attachmentFName[0]).toString());
IOUtils.copy(a.getInputStream(), fos);
fos.close();
} catch (IOException e) {
logger.info("attachment error: {}", e);
}
});
String[] inReplyToHeaders = msg.getHeader("In-Reply-To");
if (inReplyToHeaders != null && inReplyToHeaders.length > 0) {
Scanner inReplyToScanner = new Scanner(inReplyToHeaders[0].trim()).useDelimiter(EmailManager.MSGID_PATTERN);
int mid = Integer.parseInt(inReplyToScanner.next());
int rid = Integer.parseInt(inReplyToScanner.next());
logger.info("Message is reply to #{}/{}", mid, rid);
body[0] = rid > 0 ? String.format("#%d/%d %s", mid, rid, body[0])
: String.format("#%d %s", mid, body[0]);
}
URI attachmentUri = StringUtils.isNotEmpty(attachmentFName[0]) ? URI.create(String.format("juick://%s", attachmentFName[0]))
: URI.create(StringUtils.EMPTY);
commandsManager.processCommand(visitor, body[0], attachmentUri);
} else {
if (!Arrays.asList(ignoredEmails).contains(from)) {
String verificationCode = RandomStringUtils.randomAlphanumeric(8).toUpperCase();
emailService.addVerificationCode(null, from, verificationCode);
String signupUrl = String.format("Follow this link to create Juick account: https://juick.com/signup?type=email&hash=%s", verificationCode);
emailManager.sendEmail(from, "Juick registration", signupUrl, StringUtils.EMPTY, Collections.emptyMap());
}
}
} else {
throw new HttpForbiddenException();
}
}
}
|