maddy icon indicating copy to clipboard operation
maddy copied to clipboard

Dear maddy author, please tell me about the function of batch creating users.

Open cplasfwst opened this issue 1 year ago • 3 comments

Dear maddy author, please tell me about the function of batch creating users. I currently have a requirement to have the golang program automatically create users. I tried to directly insert the database credentials.db, but the inserted database user could not log in normally. I would like to ask for guidance on how I should do this so that I can automatically generate users without having to manually go to the terminal to create new users.

acd7b30297cc99c81313979e774b75dc

I inserted this picture using the program, but I can't log in normally

cplasfwst avatar Nov 23 '24 03:11 cplasfwst

about code: `package main

import ( "crypto/rand" "database/sql" "fmt" "log" "math/big"

_ "github.com/mattn/go-sqlite3"
"golang.org/x/crypto/bcrypt"

)

const ( emailDomain = "@xxxx.org" // 邮箱后缀 numAccounts = 10 // 要生成的账号数量 password = "123456" // 统一密码 dbPath = "credentials.db" // 数据库路径 )

// 生成随机的5位数字用户名 func generateRandomUsername() (string, error) { const digits = "0123456789" length := 5 username := make([]byte, length)

for i := 0; i < length; i++ {
	num, err := rand.Int(rand.Reader, big.NewInt(int64(len(digits))))
	if err != nil {
		return "", err
	}
	username[i] = digits[num.Int64()]
}

return string(username), nil

}

// 生成 bcrypt 哈希密码并添加前缀 func hashPassword(password string) (string, error) { hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return "", err } // 添加 "bcrypt:" 前缀 return "bcrypt:" + string(hashedPassword), nil }

// 添加用户到数据库 func addUser(db *sql.DB, key, value string) error { query := INSERT INTO passwords (key, value) VALUES (?, ?) _, err := db.Exec(query, key, value) return err }

func main() { // 打开数据库连接 db, err := sql.Open("sqlite3", dbPath) if err != nil { log.Fatalf("Failed to open database: %v", err) } defer db.Close()

// 开始生成用户
for i := 0; i < numAccounts; i++ {
	username, err := generateRandomUsername()
	if err != nil {
		log.Printf("Failed to generate username: %v\n", err)
		continue
	}

	email := username + emailDomain // 构造邮箱账号

	hashedPassword, err := hashPassword(password)
	if err != nil {
		log.Printf("Failed to hash password for %s: %v\n", email, err)
		continue
	}

	err = addUser(db, email, hashedPassword)
	if err != nil {
		log.Printf("Failed to add user %s: %v\n", email, err)
	} else {
		fmt.Printf("User %s added successfully\n", email)
	}
}

} `

cplasfwst avatar Nov 23 '24 03:11 cplasfwst

You can do something what I did with the password reset for Maddy specifically: https://github.com/hugmouse/maddy-password-reset/blob/master/main.go#L269

Instead of handling SQL yourself - use CLI that Maddy provides: https://maddy.email/tutorials/setting-up/#user-accounts-and-maddy-command

hugmouse avatar Nov 23 '24 08:11 hugmouse

Created a minimal config to test it:

imap tcp://127.0.0.1:4444 {
        auth pass_table sql_table {
                driver sqlite3
                dsn credentials.db
                table_name passwords
        }
        storage imapsql sqlite3 test.db
}
$ sqlite3 credentials.db
sqlite>insert into passwords values ('[email protected]', 'bcrypt:$2a$10$HKhtEhpiroRvtJzcLicGAuRh8pEz6mux4qu6SRHIRsVtM7WgFk/9y');

bcrypt value is of "12345", generated using https://www.bcryptcalculator.com/encode I am able to login to IMAP using [email protected]:12345.

foxcpp avatar Jan 25 '25 12:01 foxcpp