From 51566f13995a68d764ae7ba5424a35e62c209985 Mon Sep 17 00:00:00 2001 From: Maxim Lebedev Date: Mon, 12 Feb 2018 15:46:57 +0500 Subject: [PATCH] :sparkles: Added login package For parsing User data from url.Values and validation. close #4 --- login/check_authorization.go | 37 ++++++++++++++++++++++++++++++++ login/doc.go | 3 +++ login/new.go | 41 ++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 login/check_authorization.go create mode 100644 login/doc.go create mode 100644 login/new.go diff --git a/login/check_authorization.go b/login/check_authorization.go new file mode 100644 index 0000000..014c832 --- /dev/null +++ b/login/check_authorization.go @@ -0,0 +1,37 @@ +package login + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "fmt" +) + +// CheckAuthorization verify the authentication and the integrity of the data +// received by comparing the received hash parameter with the hexadecimal +// representation of the HMAC-SHA-256 signature of the data-check-string with the +// SHA256 hash of the bot's token used as a secret key. +func (user *User) CheckAuthorization(botToken string) (bool, error) { + dataCheckString := fmt.Sprint( + "auth_date=", user.AuthDate.Unix(), + "\n", "first_name=", user.FirstName, + // Eliminate 'hash' to avoid recursion and incorrect data validation. + "\n", "id=", user.ID, + ) + + // Add optional values if exist + if user.LastName != "" { + dataCheckString += fmt.Sprint("\n", "last_name=", user.LastName) + } + if user.PhotoURL != "" { + dataCheckString += fmt.Sprint("\n", "photo_url=", user.PhotoURL) + } + if user.Username != "" { + dataCheckString += fmt.Sprint("\n", "username=", user.Username) + } + + secretKey := sha256.Sum256([]byte(botToken)) + hash := hmac.New(sha256.New, secretKey[0:]) + _, err := hash.Write([]byte(dataCheckString)) + return hex.EncodeToString(hash.Sum(nil)) == user.Hash, err +} diff --git a/login/doc.go b/login/doc.go new file mode 100644 index 0000000..155d5af --- /dev/null +++ b/login/doc.go @@ -0,0 +1,3 @@ +// Package login contains methods for obtaining structure of the user data and +// its validation. +package login diff --git a/login/new.go b/login/new.go new file mode 100644 index 0000000..dcfa782 --- /dev/null +++ b/login/new.go @@ -0,0 +1,41 @@ +package login + +import ( + "net/url" + "strconv" + "time" +) + +// User contains data about authenticated user. +type User struct { + AuthDate time.Time `json:"auth_date"` + FirstName string `json:"first_name"` + Hash string `json:"hash"` + ID int `json:"id"` + LastName string `json:"last_name,omitempty"` + PhotoURL string `json:"photo_url,omitempty"` + Username string `json:"username,omitempty"` +} + +// New create User structure from input url.Values. +func New(src url.Values) (*User, error) { + authDate, err := strconv.Atoi(src.Get("auth_date")) + if err != nil { + return nil, err + } + + id, err := strconv.Atoi(src.Get("id")) + if err != nil { + return nil, err + } + + return &User{ + AuthDate: time.Unix(int64(authDate), 0), + FirstName: src.Get("first_name"), + Hash: src.Get("hash"), + ID: id, + LastName: src.Get("last_name"), + PhotoURL: src.Get("photo_url"), + Username: src.Get("username"), + }, nil +}