Initial commit: hotpcalc CLI
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// SerialLength — длина серийного номера eToken PASS в символах.
|
||||
SerialLength = 14
|
||||
// DefaultSerialPrefix — префикс серийных номеров eToken PASS.
|
||||
DefaultSerialPrefix = "000400"
|
||||
// SeedBytes — длина вектора инициализации в байтах.
|
||||
SeedBytes = 20
|
||||
)
|
||||
|
||||
// NewSeed генерирует криптографически стойкий вектор инициализации.
|
||||
func NewSeed(n int) ([]byte, error) {
|
||||
if n <= 0 {
|
||||
n = SeedBytes
|
||||
}
|
||||
b := make([]byte, n)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return nil, fmt.Errorf("не удалось получить случайные данные: %w", err)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// NewSerial генерирует серийный номер: заданный префикс и случайный
|
||||
// шестнадцатеричный хвост до общей длины SerialLength.
|
||||
func NewSerial(prefix string) (string, error) {
|
||||
prefix = strings.ToUpper(strings.TrimSpace(prefix))
|
||||
if err := ValidateSerial(prefix + "0"); err != nil {
|
||||
return "", fmt.Errorf("некорректный префикс серийного номера: %w", err)
|
||||
}
|
||||
|
||||
suffix := SerialLength - len(prefix)
|
||||
if suffix < 4 {
|
||||
suffix = 4
|
||||
}
|
||||
b := make([]byte, (suffix+1)/2)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return "", fmt.Errorf("не удалось получить случайные данные: %w", err)
|
||||
}
|
||||
return prefix + strings.ToUpper(hex.EncodeToString(b))[:suffix], nil
|
||||
}
|
||||
|
||||
// NewUniqueSerial подбирает серийный номер, которого ещё нет в хранилище.
|
||||
func (s *Store) NewUniqueSerial(prefix string) (string, error) {
|
||||
for i := 0; i < 100; i++ {
|
||||
serial, err := NewSerial(prefix)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if s.file.Section(serial) == nil {
|
||||
return serial, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("не удалось подобрать свободный серийный номер с префиксом %q", prefix)
|
||||
}
|
||||
Reference in New Issue
Block a user