|
|
@@ -0,0 +1,153 @@
|
|
|
+package main
|
|
|
+
|
|
|
+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 main() {
|
|
|
+ fmt.Println("Compiled")
|
|
|
+}
|