diff --git a/net/server/internal/api_account.go b/net/server/internal/api_account.go index 9234e355..7d77d72a 100644 --- a/net/server/internal/api_account.go +++ b/net/server/internal/api_account.go @@ -13,11 +13,6 @@ import ( "net/http" ) -func AddAccountApp(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json; charset=UTF-8") - w.WriteHeader(http.StatusOK) -} - func AddAccountAuthentication(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") w.WriteHeader(http.StatusOK) diff --git a/net/server/internal/api_addAccount.go b/net/server/internal/api_addAccount.go index 41479d11..91c6034b 100644 --- a/net/server/internal/api_addAccount.go +++ b/net/server/internal/api_addAccount.go @@ -4,12 +4,14 @@ import ( "net/http" "crypto/sha256" "encoding/hex" + "gorm.io/gorm" "databag/internal/store" ) func AddAccount(w http.ResponseWriter, r *http.Request) { - if _, err := BearerAccountToken(r); err != nil { + token, res := BearerAccountToken(r); + if res != nil || token.TokenType != "create" { LogMsg("authentication failed") w.WriteHeader(http.StatusUnauthorized) return @@ -51,8 +53,19 @@ func AddAccount(w http.ResponseWriter, r *http.Request) { Password: password, Guid: fingerprint, }; - if res := store.DB.Create(&account).Error; res != nil { - LogMsg("failed to store account") + + // save account and delete token + err = store.DB.Transaction(func(tx *gorm.DB) error { + if res := store.DB.Create(&account).Error; res != nil { + return res; + } + if res := store.DB.Delete(token).Error; res != nil { + return res; + } + return nil; + }); + if err != nil { + LogMsg("failed to create account"); w.WriteHeader(http.StatusInternalServerError) return } diff --git a/net/server/internal/api_addAccountApp.go b/net/server/internal/api_addAccountApp.go new file mode 100644 index 00000000..70c7f74d --- /dev/null +++ b/net/server/internal/api_addAccountApp.go @@ -0,0 +1,41 @@ +package databag + +import ( + "net/http" + "time" + "encoding/hex" + "databag/internal/store" + "github.com/theckman/go-securerandom" +) + +func AddAccountApp(w http.ResponseWriter, r *http.Request) { + + id, err := AccountLogin(r) + if err != nil { + LogMsg("failed to login") + w.WriteHeader(http.StatusUnauthorized); + return + } + + data, res := securerandom.Bytes(4) + if res != nil { + LogMsg("failed to generate token") + w.WriteHeader(http.StatusInternalServerError) + return + } + + token := store.AccountToken{ + AccountID: id, + TokenType: "attach", + Token: hex.EncodeToString(data), + Expires: time.Now().Unix() + APP_ATTACHEXPIRE, + }; + if store.DB.Create(&token).Error != nil { + LogMsg("failed to store token") + w.WriteHeader(http.StatusInternalServerError) + return + } + + WriteResponse(w, data); +} + diff --git a/net/server/internal/api_addNodeAccount.go b/net/server/internal/api_addNodeAccount.go index afc94e8b..32c100e2 100644 --- a/net/server/internal/api_addNodeAccount.go +++ b/net/server/internal/api_addNodeAccount.go @@ -2,6 +2,8 @@ package databag import ( "net/http" + "encoding/hex" + "time" "databag/internal/store" "github.com/theckman/go-securerandom" ) @@ -14,20 +16,26 @@ func AddNodeAccount(w http.ResponseWriter, r *http.Request) { return } - data, err := securerandom.Base64OfBytes(32) + data, err := securerandom.Bytes(16) if err != nil { LogMsg("failed to generate token"); w.WriteHeader(http.StatusInternalServerError); return } + token := hex.EncodeToString(data) - token := store.AccountToken{TokenType: "create", Token: data }; - if res := store.DB.Create(&token).Error; res != nil { + accountToken := store.AccountToken{ + TokenType: "create", + Token: token, + Expires: time.Now().Unix() + APP_CREATEEXPIRE, + }; + + if store.DB.Create(&accountToken).Error != nil { LogMsg("failed to store token"); w.WriteHeader(http.StatusInternalServerError); return } - WriteResponse(w, data); + WriteResponse(w, token); } diff --git a/net/server/internal/api_getAccountUsername.go b/net/server/internal/api_getAccountUsername.go index de9806ed..e6060c76 100644 --- a/net/server/internal/api_getAccountUsername.go +++ b/net/server/internal/api_getAccountUsername.go @@ -11,9 +11,9 @@ type accountUsername struct { func GetAccountUsername(w http.ResponseWriter, r *http.Request) { - _, err := BearerAccountToken(r); - if err != nil { - LogMsg("authentication failed") + token, err := BearerAccountToken(r); + if err != nil || (token.TokenType != "create" && token.TokenType != "reset") { + LogMsg("invalid token") w.WriteHeader(http.StatusUnauthorized) return } diff --git a/net/server/internal/appValues.go b/net/server/internal/appValues.go index 7b1f5133..1a1c8f8b 100644 --- a/net/server/internal/appValues.go +++ b/net/server/internal/appValues.go @@ -2,4 +2,5 @@ package databag const APP_BODYLIMIT = 1048576 const APP_VERSION = "0.0.1" - +const APP_ATTACHEXPIRE = 300 +const APP_CREATEEXPIRE = 86400 diff --git a/net/server/internal/auth.go b/net/server/internal/auth.go index 6f7ce043..0be3e8a6 100644 --- a/net/server/internal/auth.go +++ b/net/server/internal/auth.go @@ -3,12 +3,19 @@ package databag import ( "errors" "strings" + "time" "net/http" "encoding/base64" "golang.org/x/crypto/bcrypt" "databag/internal/store" ) +type accountLogin struct { + ID uint + Password []byte + Expires int64 +} + func AdminLogin(r *http.Request) bool { // extract request auth @@ -36,6 +43,28 @@ func AdminLogin(r *http.Request) bool { return true; } +func AccountLogin(r *http.Request) (uint, error) { + + // extract request auth + username, password, ok := r.BasicAuth(); + if !ok || username == "" || password == "" { + return 0, errors.New("invalid login") + } + + // find account + var account accountLogin + if store.DB.Model(&Account{}).Where("Username = ?", username).First(&account).Error != nil { + return 0, errors.New("username not found"); + } + + // compare password + if bcrypt.CompareHashAndPassword(account.Password, []byte(password)) != nil { + return 0, errors.New("invalid password"); + } + + return account.ID, nil +} + func BearerAccountToken(r *http.Request) (store.AccountToken, error) { // parse bearer authentication @@ -45,6 +74,9 @@ func BearerAccountToken(r *http.Request) (store.AccountToken, error) { // find token record var accountToken store.AccountToken err := store.DB.Where("token = ?", token).First(&accountToken).Error + if accountToken.Expires < time.Now().Unix() { + return accountToken, errors.New("expired token") + } return accountToken, err } @@ -76,7 +108,7 @@ func BasicCredentials(r *http.Request) (string, []byte, error) { password, err = bcrypt.GenerateFromPassword([]byte(login[1]), bcrypt.DefaultCost) if err != nil { LogMsg("failed to hash password") - return username, password, err + return username, password, err } return username, password, nil diff --git a/net/server/internal/store/schema.go b/net/server/internal/store/schema.go index 9ce57f38..f970e98d 100644 --- a/net/server/internal/store/schema.go +++ b/net/server/internal/store/schema.go @@ -40,6 +40,7 @@ type AccountToken struct { AccountID uint `gorm:"index"` TokenType string `gorm:"not null; ` Token string `gorm:"not null;uniqueIndex"` + Expires int64 `gorm:"not null"` Created int64 `gorm:"autoCreateTime"` Account Account }