mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-02-18 21:10:57 +08:00
feat: add Telegram authentication
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user