mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-09-01 00:44:02 +03:00
FILE / ScuroNeko/mtg
mtglib/secret.go
Исходный файл и его история в репозитории.
115 lines
2.0 KiB
Go
115 lines
2.0 KiB
Go
package mtglib
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
SecretKeyLength = 16
|
|
|
|
secretFakeTLSFirstByte byte = 238
|
|
)
|
|
|
|
var secretEmptyKey [SecretKeyLength]byte
|
|
|
|
type Secret struct {
|
|
Key [SecretKeyLength]byte
|
|
Host string
|
|
}
|
|
|
|
func (s Secret) MarshalText() ([]byte, error) {
|
|
if s.Valid() {
|
|
return []byte(s.String()), nil
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
func (s *Secret) UnmarshalText(data []byte) error {
|
|
text := string(data)
|
|
if text == "" {
|
|
return ErrSecretEmpty
|
|
}
|
|
|
|
var (
|
|
decoded []byte
|
|
err error
|
|
)
|
|
|
|
if strings.HasPrefix(text, "ee") {
|
|
decoded, err = hex.DecodeString(strings.TrimPrefix(text, "ee"))
|
|
}
|
|
|
|
if err != nil || len(decoded) <= SecretKeyLength {
|
|
decoded, err = base64.RawURLEncoding.DecodeString(text)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("incorrect secret format: %w", err)
|
|
}
|
|
|
|
if len(decoded) <= SecretKeyLength {
|
|
return fmt.Errorf("secret has incorrect length %d", len(text))
|
|
}
|
|
|
|
if decoded[0] != secretFakeTLSFirstByte {
|
|
return fmt.Errorf("incorrect first byte: %v", decoded[0])
|
|
}
|
|
|
|
decoded = decoded[1:]
|
|
}
|
|
|
|
copy(s.Key[:], decoded[:SecretKeyLength])
|
|
s.Host = string(decoded[SecretKeyLength:])
|
|
|
|
if s.Host == "" {
|
|
return fmt.Errorf("hostname cannot be empty: %s", text)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s Secret) Valid() bool {
|
|
return s.Key != secretEmptyKey && s.Host != ""
|
|
}
|
|
|
|
func (s Secret) String() string {
|
|
return s.Base64()
|
|
}
|
|
|
|
func (s Secret) Base64() string {
|
|
return base64.RawURLEncoding.EncodeToString(s.makeBytes())
|
|
}
|
|
|
|
func (s Secret) Hex() string {
|
|
return hex.EncodeToString(s.makeBytes())
|
|
}
|
|
|
|
func (s *Secret) makeBytes() []byte {
|
|
data := append([]byte{secretFakeTLSFirstByte}, s.Key[:]...)
|
|
data = append(data, s.Host...)
|
|
|
|
return data
|
|
}
|
|
|
|
func GenerateSecret(hostname string) Secret {
|
|
s := Secret{
|
|
Host: hostname,
|
|
}
|
|
|
|
if _, err := rand.Read(s.Key[:]); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
func ParseSecret(secret string) (Secret, error) {
|
|
s := Secret{}
|
|
|
|
return s, s.UnmarshalText([]byte(secret))
|
|
}
|