174 lines
5.2 KiB
Go
174 lines
5.2 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"fmt"
|
|
"math/big"
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"code.gitea.io/sdk/gitea"
|
|
"github.com/bwmarrin/discordgo"
|
|
)
|
|
|
|
var (
|
|
discordToken string
|
|
giteaToken string
|
|
giteaURL string
|
|
)
|
|
|
|
func main() {
|
|
|
|
giteaToken = os.Getenv("GITEA_TOKEN")
|
|
giteaURL = os.Getenv("GITEA_URL")
|
|
discordToken = os.Getenv("DISCORD_TOKEN")
|
|
|
|
if giteaToken == "" || giteaURL == "" || discordToken == "" {
|
|
fmt.Println("Environment variables GITEA_TOKEN, GITEA_URL, and DISCORD_TOKEN must be set.")
|
|
os.Exit(1)
|
|
}
|
|
|
|
dg, err := discordgo.New("Bot " + discordToken)
|
|
if err != nil {
|
|
fmt.Println("error creating Discord session,", err)
|
|
return
|
|
}
|
|
|
|
dg.Identify.Intents = discordgo.IntentsGuildMessages | discordgo.IntentsDirectMessages
|
|
dg.AddHandler(messageCreate)
|
|
|
|
err = dg.Open()
|
|
if err != nil {
|
|
fmt.Println("error opening connection,", err)
|
|
return
|
|
}
|
|
|
|
fmt.Println("Bot is now running. Press CTRL+C to exit.")
|
|
select {}
|
|
}
|
|
|
|
// validateUsername checks if the username complies with Gitea requirements
|
|
func validateUsername(username string) (bool, error) {
|
|
// Regular expression for valid username
|
|
var validUsernameRegex = regexp.MustCompile(`^[a-zA-Z0-9]+([_.-]?[a-zA-Z0-9]+)*$`)
|
|
|
|
// Check length constraints (1 to 39 characters)
|
|
if len(username) < 1 || len(username) > 39 {
|
|
return false, nil
|
|
}
|
|
|
|
return validUsernameRegex.MatchString(username), nil
|
|
}
|
|
|
|
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
|
// Ignore messages from the bot itself
|
|
if m.Author.ID == s.State.User.ID {
|
|
return
|
|
}
|
|
|
|
// Check if the command is !register
|
|
if strings.HasPrefix(m.Content, "!register") {
|
|
args := strings.Fields(m.Content)
|
|
|
|
var username, email string
|
|
|
|
// Loop through arguments to find username and email
|
|
for _, arg := range args[1:] { // Skip the command itself
|
|
if strings.HasPrefix(arg, "--username=") {
|
|
username = strings.TrimPrefix(arg, "--username=")
|
|
} else if strings.HasPrefix(arg, "--email=") {
|
|
email = strings.TrimPrefix(arg, "--email=")
|
|
}
|
|
}
|
|
|
|
// If no username parameter is provided, use the user's Discord nickname or username
|
|
if username == "" {
|
|
member, err := s.GuildMember(m.GuildID, m.Author.ID)
|
|
if err != nil {
|
|
username = m.Author.Username
|
|
} else if member.Nick != "" {
|
|
username = member.Nick
|
|
} else {
|
|
username = m.Author.Username
|
|
}
|
|
}
|
|
|
|
// Remove trailing period from username if present
|
|
username = strings.TrimRight(username, ".")
|
|
|
|
// If no email parameter is provided, use the default email format
|
|
if email == "" {
|
|
email = fmt.Sprintf("%s@git.beisel.it", username)
|
|
}
|
|
|
|
// Validate the username
|
|
isValid, err := validateUsername(username)
|
|
if err != nil {
|
|
s.ChannelMessageSend(m.ChannelID, "Invalid username. Username must consist of alphanumeric characters, dashes, underscores, and dots. It cannot begin or end with non-alphanumeric characters, and consecutive non-alphanumeric characters are forbidden.")
|
|
return
|
|
}
|
|
if !isValid {
|
|
s.ChannelMessageSend(m.ChannelID, "Invalid username. Username must consist of alphanumeric characters, dashes, underscores, and dots. It cannot begin or end with non-alphanumeric characters, and consecutive non-alphanumeric characters are forbidden.")
|
|
return
|
|
}
|
|
|
|
fmt.Println("Creating user:", username)
|
|
|
|
// Auto-generate a password
|
|
password, err := generatePassword(12) // You can choose the length of the password
|
|
if err != nil {
|
|
s.ChannelMessageSend(m.ChannelID, "Failed to generate a secure password.")
|
|
return
|
|
}
|
|
|
|
// Create user in Gitea
|
|
err = createUserInGitea(username, email, password)
|
|
if err != nil {
|
|
s.ChannelMessageSend(m.ChannelID, "Failed to create user in Gitea.")
|
|
return
|
|
}
|
|
|
|
// Send DM with login details and instructions
|
|
dmChannel, err := s.UserChannelCreate(m.Author.ID)
|
|
if err != nil {
|
|
s.ChannelMessageSend(m.ChannelID, "Failed to send DM.")
|
|
return
|
|
}
|
|
|
|
dmMessage := fmt.Sprintf("You can now log in to %s using:\n\nUsername: %s\nPassword: %s\n\nYour E-Mail has temporarily been set to \"%s\". Please make sure to set this to your correct e-mail address and update your password immediately.", giteaURL, username, password, email)
|
|
_, err = s.ChannelMessageSend(dmChannel.ID, dmMessage)
|
|
if err != nil {
|
|
s.ChannelMessageSend(m.ChannelID, "Failed to send login details via DM.")
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// generatePassword creates a secure, random password of a given length.
|
|
func generatePassword(length int) (string, error) {
|
|
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
|
var password strings.Builder
|
|
for i := 0; i < length; i++ {
|
|
charIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
password.WriteByte(charset[charIndex.Int64()])
|
|
}
|
|
return password.String(), nil
|
|
}
|
|
|
|
func createUserInGitea(username, email, password string) error {
|
|
client, _ := gitea.NewClient(giteaURL, gitea.SetToken(giteaToken))
|
|
|
|
_, _, err := client.AdminCreateUser(gitea.CreateUserOption{
|
|
LoginName: username,
|
|
Username: username,
|
|
Email: email,
|
|
Password: password,
|
|
})
|
|
|
|
return err
|
|
}
|