package auth import ( "crypto/rand" "crypto/sha256" "encoding/base64" "encoding/hex" "encoding/json" "goseg/config" "fmt" "time" "golang.org/x/crypto/nacl/secretbox" ) // CheckToken checks the validity of the token. func CheckToken(token string, websocket interface{}, setup bool) (bool, string, error) { if token == "" { authStatus := false if setup { authStatus = true } newToken, err := CreateToken(websocket, setup) if err != nil { return false, "", err } return authStatus, newToken["token"], nil } // Token verification logic here... // ... return false, "", nil } // CreateToken creates a new session token. func CreateToken(websocket interface{}, setup bool) (map[string]string, error) { // placeholder logic for IP and UserAgent ip := "localhost" userAgent := "lick" // if more properties are needed from websocket, you can extract them here conf := config.Conf() key := conf.KeyFile // generate random strings for id, secret, and padding id := NewSecretString(32) secret := NewSecretString(128) padding := NewSecretString(32) contents := map[string]string{ "id": id, "ip": ip, "user_agent": userAgent, "secret": secret, "padding": padding, "authorized": fmt.Sprintf("%v", setup), "created": time.Now().Format("2006-01-02_15:04:05"), } // encrypt the contents encryptedText, err := KeyfileEncrypt(contents, key) if err != nil { return nil, fmt.Errorf("failed to encrypt token: %v", err) } // and hash hashed := sha256.Sum256([]byte(encryptedText)) // Update sessions in the system's configuration now := time.Now().Format("2006-01-02_15:04:05") if setup { updates := map[string]interface{}{ "Sessions": map[string]interface{}{ "Authorized": map[string]string{ "Hash": hex.EncodeToString(hashed[:]), "Created": now, }, }, } config.UpdateConf(updates) } else { updates := map[string]interface{}{ "Sessions": map[string]interface{}{ "Unauthorized": map[string]string{ "Hash": hex.EncodeToString(hashed[:]), "Created": now, }, }, } config.UpdateConf(updates) } return map[string]string{ "id": id, "token": encryptedText, }, nil } // encrypt the contents using stored keyfile val func KeyfileEncrypt(contents map[string]string, key string) (string, error) { contentBytes, err := json.Marshal(contents) if err != nil { return "", err } // convert key to bytes keyBytes := []byte(key) if len(keyBytes) != 32 { return "", fmt.Errorf("key must be 32 bytes in length") } var keyArray [32]byte copy(keyArray[:], keyBytes) // generate nonce var nonce [24]byte if _, err := rand.Read(nonce[:]); err != nil { return "", err } // encrypt contents encrypted := secretbox.Seal(nonce[:], contentBytes, &nonce, &keyArray) return base64.URLEncoding.EncodeToString(encrypted), nil } // decrypt routine func KeyfileDecrypt(encryptedText string, key string) (map[string]string, error) { // get bytes keyBytes := []byte(key) var keyArray [32]byte copy(keyArray[:], keyBytes) encryptedBytes, err := base64.URLEncoding.DecodeString(encryptedText) if err != nil { return nil, err } // get nonce var nonce [24]byte copy(nonce[:], encryptedBytes[:24]) // attempt decrypt decrypted, ok := secretbox.Open(nil, encryptedBytes[24:], &nonce, &keyArray) if !ok { return nil, fmt.Errorf("Decryption failed") } var contents map[string]string if err := json.Unmarshal(decrypted, &contents); err != nil { return nil, err } return contents, nil } // NewSecretString generates a random secret string of the given length. func NewSecretString(length int) string { randBytes := make([]byte, length) _, err := rand.Read(randBytes) if err != nil { return "" } return base64.URLEncoding.EncodeToString(randBytes) } func auth() { fmt.Println("Compiled") }