mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-02-08 08:01:16 +08:00
103 lines
4.0 KiB
Java
103 lines
4.0 KiB
Java
package com.openisle.service;
|
|
|
|
import com.openisle.dto.TelegramLoginRequest;
|
|
import com.openisle.model.RegisterMode;
|
|
import com.openisle.model.Role;
|
|
import com.openisle.model.User;
|
|
import com.openisle.repository.UserRepository;
|
|
import lombok.RequiredArgsConstructor;
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
import javax.crypto.Mac;
|
|
import javax.crypto.spec.SecretKeySpec;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.security.MessageDigest;
|
|
import java.util.*;
|
|
|
|
@Service
|
|
@RequiredArgsConstructor
|
|
public class TelegramAuthService {
|
|
private final UserRepository userRepository;
|
|
private final AvatarGenerator avatarGenerator;
|
|
|
|
@Value("${telegram.bot-token:}")
|
|
private String botToken;
|
|
|
|
public Optional<AuthResult> authenticate(TelegramLoginRequest req, RegisterMode mode, boolean viaInvite) {
|
|
try {
|
|
if (botToken == null || botToken.isEmpty()) {
|
|
return Optional.empty();
|
|
}
|
|
String dataCheckString = buildDataCheckString(req);
|
|
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
|
byte[] secretKey = md.digest(botToken.getBytes(StandardCharsets.UTF_8));
|
|
Mac mac = Mac.getInstance("HmacSHA256");
|
|
mac.init(new SecretKeySpec(secretKey, "HmacSHA256"));
|
|
byte[] hash = mac.doFinal(dataCheckString.getBytes(StandardCharsets.UTF_8));
|
|
String hex = bytesToHex(hash);
|
|
if (!hex.equalsIgnoreCase(req.getHash())) {
|
|
return Optional.empty();
|
|
}
|
|
String username = req.getUsername();
|
|
String email = (username != null ? username : req.getId()) + "@telegram.org";
|
|
String avatar = req.getPhotoUrl();
|
|
return Optional.of(processUser(email, username, avatar, mode, viaInvite));
|
|
} catch (Exception e) {
|
|
return Optional.empty();
|
|
}
|
|
}
|
|
|
|
private String buildDataCheckString(TelegramLoginRequest req) {
|
|
List<String> data = new ArrayList<>();
|
|
if (req.getAuthDate() != null) data.add("auth_date=" + req.getAuthDate());
|
|
if (req.getFirstName() != null) data.add("first_name=" + req.getFirstName());
|
|
if (req.getId() != null) data.add("id=" + req.getId());
|
|
if (req.getLastName() != null) data.add("last_name=" + req.getLastName());
|
|
if (req.getPhotoUrl() != null) data.add("photo_url=" + req.getPhotoUrl());
|
|
if (req.getUsername() != null) data.add("username=" + req.getUsername());
|
|
Collections.sort(data);
|
|
return String.join("\n", data);
|
|
}
|
|
|
|
private String bytesToHex(byte[] bytes) {
|
|
StringBuilder sb = new StringBuilder();
|
|
for (byte b : bytes) {
|
|
sb.append(String.format("%02x", b));
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
private AuthResult processUser(String email, String username, String avatar, RegisterMode mode, boolean viaInvite) {
|
|
Optional<User> existing = userRepository.findByEmail(email);
|
|
if (existing.isPresent()) {
|
|
User user = existing.get();
|
|
if (!user.isVerified()) {
|
|
user.setVerified(true);
|
|
user.setVerificationCode(null);
|
|
userRepository.save(user);
|
|
}
|
|
return new AuthResult(user, false);
|
|
}
|
|
String baseUsername = username != null ? username : email.split("@")[0];
|
|
String finalUsername = baseUsername;
|
|
int suffix = 1;
|
|
while (userRepository.findByUsername(finalUsername).isPresent()) {
|
|
finalUsername = baseUsername + suffix++;
|
|
}
|
|
User user = new User();
|
|
user.setUsername(finalUsername);
|
|
user.setEmail(email);
|
|
user.setPassword("");
|
|
user.setRole(Role.USER);
|
|
user.setVerified(true);
|
|
user.setApproved(mode == RegisterMode.DIRECT || viaInvite);
|
|
if (avatar != null) {
|
|
user.setAvatar(avatar);
|
|
} else {
|
|
user.setAvatar(avatarGenerator.generate(finalUsername));
|
|
}
|
|
return new AuthResult(userRepository.save(user), true);
|
|
}
|
|
}
|