| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- package auth
- import (
- "crypto/rand"
- "crypto/sha256"
- "encoding/base64"
- "encoding/hex"
- "encoding/json"
- "goseg/config"
- "fmt"
- "time"
- "sync"
- "github.com/gorilla/websocket"
- "golang.org/x/crypto/nacl/secretbox"
- )
- var (
- AuthenticatedClients = struct{
- Conns map[*websocket.Conn]bool
- sync.Mutex
- }{
- Conns: make(map[*websocket.Conn]bool),
- }
- )
- // CheckToken checks the validity of the token.
- func CheckToken(token string, conn *websocket.Conn, setup bool) (bool, string, error) {
- if token == "" {
- authStatus := false
- if setup {
- authStatus = true
- }
- newToken, err := CreateToken(conn, 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(conn *websocket.Conn, 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 Hasher(password string) string {
- conf := config.Conf()
- salt := conf.Salt
- toHash := password + salt
- res := sha256.Sum256([]byte(toHash))
- return hex.EncodeToString(res[:])
- }
- func AuthenticateLogin(password string) bool {
- conf := config.Conf()
- if Hasher(password) == conf.PwHash {
- return true
- } else {
- return false
- }
- }
- func WsIsAuthenticated(conn *websocket.Conn) bool {
- AuthenticatedClients.Lock()
- _, exists := AuthenticatedClients.Conns[conn]
- AuthenticatedClients.Unlock()
- return exists
- }
|