invalid memory address or nil pointer dereference on QueryRow - go

I'm new to go and trying to create a signin function, When trying to query row from the database I get this error: runtime error: invalid memory address or nil pointer dere
ference
The crash caused by this line:
result := db.QueryRow("SELECT password FROM users WHERE email=$1", credentials.Email)
This is the code:
type Credentials struct {
Email string `json:"email", db:"email"`
Password string `json:"password", db:"password"`
}
func SignIn(w http.ResponseWriter, r *http.Request) {
credentials := &Credentials{}
err := json.NewDecoder(r.Body).Decode(credentials)
if err != nil {
// If there is something wrong with the request body, return a 400 status
w.WriteHeader(http.StatusBadRequest)
return
}
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+"dbname=%s sslmode=disable", dbInfo.Host, dbInfo.Port, dbInfo.User, dbInfo.DBname)
db, err := sql.Open("postgres", psqlInfo)
println(credentials.Email)
result := db.QueryRow("SELECT password FROM users WHERE email=$1", credentials.Email)
defer db.Close()
if err != nil {
//If there is an issue with the database, return a 500 error.
w.WriteHeader(http.StatusInternalServerError)
return
}
//We create another instance of 'Credentials' t store the credentials we get from the database
storedCreds := &Credentials{}
// Store the obtained password in `storedCreds`
err = result.Scan(&storedCreds.Password)
if err != nil {
// If an entry with the email does not exist, send an "Unauthorized"(401) status
if err == sql.ErrNoRows {
w.WriteHeader(http.StatusUnauthorized)
return
}
//If the error is of any other type, send a 500 status
w.WriteHeader(http.StatusInternalServerError)
return
}
if credentials.Password != storedCreds.Password {
//The two passwords does not match, return a 401 status
w.WriteHeader(http.StatusUnauthorized)
}
}
I checked and credentials.Email is not null and I can't understand what causes this error.

db, err := sql.Open("postgres", psqlInfo)
// ...
result := db.QueryRow(...)
db is probably nil because the sql.Open failed.
You're not checking err != nil like you should always do when a function returns an error type.

Related

Golang BoltDB Delete Key Seemingly Not Working

CentOS 7, Github boltdb/bolt version 1.3.1, go version go1.17.7 linux/amd64
This issue may go to a misunderstanding of how BoltDB works, or maybe I have a bug, or maybe there is an issue. I've used BoltDB before, and have had very good results. Though, I didn't explicly look for this issue. What I'm seeing is that I try to delete a key from a bucket, and the key and its value are deleted in the active db.Update, but it's still there after that db.Update is ended. Looking for any explanation of what might be going on. Seems like this functionality couldn't possibly be broken.
I am using a BoltDB bucket for storing a temporary token associated with an email address for creating a new account. Want to be tidy and clean up old data right away (expired tokens, misused tokens, etc). Pretty standard stuff. The structure for the temporary token is (the key is the temporary token, a 10 digit random character string):
(Temporary Token is the Bucket key)
type tempTokenStruct struct {
EmailAddress string `json:"emailaddress"` // Email Address to be changed
TokenExpiryTime int64 `json:"tokenexpirytime"` // Expiry Time for token in Epoch time
}
The user enters an email address in a web form and hits 'submit'. That creates a call to the REST service that creates an entry in the temporary token table, like:
"BpLnfgDsc2" => foo#bar.com, 1645650084
The service emails a URL that has the temporary token embedded, and that link takes the user to a form that allows them to put in their email address (again to verify) and new password (twice). Hitting Submit then results in the following code being called from within a web handler:
func checkTokenValid(emailAddress string, tempToken string) error {
var tempTokenData tempTokenStruct
var tempTokenBytes []byte
tempTokenBytes = []byte(tempToken)
db, err := bolt.Open(USER_DB_NAME, 0644, nil)
if err != nil {
return err
}
defer db.Close()
err = db.Update(func(tx *bolt.Tx) error {
tempTokenBucket := tx.Bucket([]byte("temptokens"))
// The bucket hasn't been created, so there are no stored tokens
if tempTokenBucket == nil {
return errors.New("Not Authorized (1): Please request a new password new/change email from the login page.")
}
// There is no matching token stored in the bucket, so this is an invalid request
tempTokenJSON := tempTokenBucket.Get(tempTokenBytes)
//[I've put a printf here: A]
if tempTokenJSON == nil {
return errors.New("Not Authorized (2): Please request a new password new/change email from the login page.")
}
jsonConvertErr := json.Unmarshal(tempTokenJSON, &tempTokenData)
if jsonConvertErr != nil {
tempTokenBucket.Delete(tempTokenBytes)
return errors.New("Not Authorized (3): Please request a new password new/change email from the login page.")
}
// Check to see if the time is expired, if so, remove the key and indicate error
if tempTokenData.TokenExpiryTime < time.Now().Unix() {
tempTokenBucket.Delete(tempTokenBytes)
//[I've put a printf here: B]
return errors.New("Not Authorized (4): Please request a new password new/change email from the login page.")
}
// Check to see if the email addresses match
if emailAddress != tempTokenData.EmailAddress {
tempTokenBucket.Delete(tempTokenBytes)
return errors.New("Not Authorized (5): Please request a new password new/change email from the login page.")
}
tempTokenBucket.Delete(tempTokenBytes)
return nil
})
// This is test code to see if the key was in fact deleted
db.Update(func(tx *bolt.Tx) error {
tempTokenBucket := tx.Bucket([]byte("temptokens"))
tempTokenJSON := tempTokenBucket.Get(tempTokenBytes)
// [I've put a printf here: C]
return nil
})
return err
}
I'm testing with a timed-out token (4), so the idea is that when it encounters that timed out token, it wants to delete this now invalid token from the bucket.
At the A location, it prints:
First Get call token BpLnfgDsc2 is {"emailaddress":"foo#bar.com","tokenexpirytime":1645650084}
At the B location I put code in that does a .Get, it prints out (looks to be deleted):
Before the DB Close (4), after deleting, token BpLnfgDsc2 is
At the C location, it prints (looks to be back):
After the DB Close, token BpLnfgDsc2 is {"emailaddress":"foo#bar.com","tokenexpirytime":1645650084}
There are no errors returned for anything. I've repeated this many times, putting fmt.Printfs everywhere to see what's going on. The results are the same, the key doesn't seem to be getting deleted. After this sits, I 'vi -b' the DB file, and the key, value is still there. Running after it sits, it still sees the key value there. I'm confused, and any pointers will be appreciated.
Update: The basic bolt functionality of Put/Get/Delete/Get works as per this test code (should be obvious):
package main
import "fmt"
import "encoding/json"
import "github.com/boltdb/bolt"
type tempTokenStruct struct {
EmailAddress string `json:"emailaddress"` // Email Address to be changed (Temporary Token is the DB key)
TokenExpiryTime int64 `json:"tokenexpirytime"` // Expiry Time for token in Epoch time
}
func main() {
var tempToken tempTokenStruct
tempToken.EmailAddress = "foo#bar.com"
tempToken.TokenExpiryTime = 1234567890
tempTokenDataJSON, jsonMarshalError := json.Marshal(tempToken)
if jsonMarshalError != nil {
fmt.Printf("JSON Marshal Error: %s\n", jsonMarshalError.Error())
return
}
tempTokenKey := []byte("foo")
db, err := bolt.Open("test.db", 0644, nil)
if err != nil {
fmt.Printf("Error opening Database\n")
return
}
defer db.Close()
// Put a key in the table
err = db.Update(func(tx *bolt.Tx) error {
tempTokenBucket, err := tx.CreateBucketIfNotExists([]byte("temptokens"))
if err != nil {
return err
}
dbPutError := tempTokenBucket.Put(tempTokenKey, []byte(tempTokenDataJSON))
return dbPutError
})
if err != nil {
fmt.Printf("Error putting key value pair into table: %s\n", err.Error())
}
// Check if the key/value is there after putting it in
err = db.Update(func(tx *bolt.Tx) error {
tempTokenBucket, err := tx.CreateBucketIfNotExists([]byte("temptokens"))
if err != nil {
return err
}
valueGet := tempTokenBucket.Get(tempTokenKey)
fmt.Printf("Value for Token: \"%s\" is \"%s\" just after putting it in there\n", tempTokenKey, valueGet)
return nil
})
// Delete that key from the table
err = db.Update(func(tx *bolt.Tx) error {
tempTokenBucket, err := tx.CreateBucketIfNotExists([]byte("temptokens"))
if err != nil {
return err
}
dbDeleteError := tempTokenBucket.Delete(tempTokenKey)
return dbDeleteError
})
if err != nil {
fmt.Printf("Error Deleting key from bucket: %s\n", err.Error())
}
// Check if the key/value is there after deleting it
err = db.Update(func(tx *bolt.Tx) error {
tempTokenBucket, err := tx.CreateBucketIfNotExists([]byte("temptokens"))
if err != nil {
return err
}
valueGet := tempTokenBucket.Get(tempTokenKey)
fmt.Printf("Value for Token: \"%s\" is \"%s\" after the delete\n", tempTokenKey, valueGet)
return nil
})
if err != nil {
fmt.Printf("Error getting key from table: %s\n", err.Error())
}
}
Prints out:
Value for Token: "foo" is "{"emailaddress":"foo#bar.com","tokenexpirytime":1234567890}" just after putting it in there
Value for Token: "foo" is "" after the delete
So, not sure why the other code doesn't work. Almost as if the delete is using a different key, but the key is the same across the other code.
I believe that the behaviour of db.Update with a non-nil return value is the confusion here. As per the docs
Inside the closure, you have a consistent view of the database. You commit the transaction by returning nil at the end. You can also rollback the transaction at any point by returning an error.
You are returning an error with:
return errors.New("Not Authorized (4): Please request a new password new/change email from the login page.")
This means that all operations within that db.Update( are rolled back. This can be replicated in your simple example with a small change (return fmt.Errorf("RETURNING ERROR HERE")):
package main
import "fmt"
import "encoding/json"
import "github.com/boltdb/bolt"
type tempTokenStruct struct {
EmailAddress string `json:"emailaddress"` // Email Address to be changed (Temporary Token is the DB key)
TokenExpiryTime int64 `json:"tokenexpirytime"` // Expiry Time for token in Epoch time
}
func main() {
var tempToken tempTokenStruct
tempToken.EmailAddress = "foo#bar.com"
tempToken.TokenExpiryTime = 1234567890
tempTokenDataJSON, jsonMarshalError := json.Marshal(tempToken)
if jsonMarshalError != nil {
fmt.Printf("JSON Marshal Error: %s\n", jsonMarshalError.Error())
return
}
tempTokenKey := []byte("foo")
db, err := bolt.Open("test.db", 0644, nil)
if err != nil {
fmt.Printf("Error opening Database\n")
return
}
defer db.Close()
// Put a key in the table
err = db.Update(func(tx *bolt.Tx) error {
tempTokenBucket, err := tx.CreateBucketIfNotExists([]byte("temptokens"))
if err != nil {
return err
}
dbPutError := tempTokenBucket.Put(tempTokenKey, []byte(tempTokenDataJSON))
return dbPutError
})
if err != nil {
fmt.Printf("Error putting key value pair into table: %s\n", err.Error())
}
// Check if the key/value is there after putting it in
err = db.Update(func(tx *bolt.Tx) error {
tempTokenBucket, err := tx.CreateBucketIfNotExists([]byte("temptokens"))
if err != nil {
return err
}
valueGet := tempTokenBucket.Get(tempTokenKey)
fmt.Printf("Value for Token: \"%s\" is \"%s\" just after putting it in there\n", tempTokenKey, valueGet)
return nil
})
// Delete that key from the table
err = db.Update(func(tx *bolt.Tx) error {
tempTokenBucket, err := tx.CreateBucketIfNotExists([]byte("temptokens"))
if err != nil {
return err
}
tempTokenBucket.Delete(tempTokenKey)
return fmt.Errorf("RETURNING ERROR HERE") // CHANGED HERE
})
if err != nil {
fmt.Printf("Error Deleting key from bucket: %s\n", err.Error())
}
// Check if the key/value is there after deleting it
err = db.Update(func(tx *bolt.Tx) error {
tempTokenBucket, err := tx.CreateBucketIfNotExists([]byte("temptokens"))
if err != nil {
return err
}
valueGet := tempTokenBucket.Get(tempTokenKey)
fmt.Printf("Value for Token: \"%s\" is \"%s\" after the delete\n", tempTokenKey, valueGet)
return nil
})
if err != nil {
fmt.Printf("Error getting key from table: %s\n", err.Error())
}
}
The output is now:
Value for Token: "foo" is "{"emailaddress":"foo#bar.com","tokenexpirytime":1234567890}" just after putting it in there
Error Deleting key from bucket: RETURNING ERROR HERE
Value for Token: "foo" is "{"emailaddress":"foo#bar.com","tokenexpirytime":1234567890}" after the delete
This appears to match what you are seeing in your main code. The fix is relatively simple - don't return an error if you want changes to be committed.

json.Marshal for http post request with echo

I have two golang servers running on localhost.
They are using different ports.
I want to create a post request on one that sends a JSON object to the other one.
I am using the echo framework (if this matters)
The error I am getting is when I try to marshal the object for the post object:
2-valued json.Marshal(data) (value of type ([]byte, error)) where single value is expected
server 1:
type SendEmail struct {
SenderName string `json:"senderName,omitempty" bson:"senderName,omitempty" validate:"required,min=3,max=128"`
SenderEmail string `json:"senderEmail" bson:"senderEmail" validate:"required,min=10,max=128"`
Subject string `json:"subject" bson:"subject" validate:"required,min=10,max=128"`
RecipientName string `json:"recipientName" bson:"recipientName" validate:"required,min=3,max=128"`
RecipientEmail string `json:"recipientEmail" bson:"recipientEmail" validate:"required,min=10,max=128"`
PlainTextContent string `json:"plainTextContent" bson:"plainTextContent" validate:"required,min=10,max=512"`
}
func resetPassword(c echo.Context) error {
email := c.Param("email")
if email == "" {
return c.String(http.StatusNotFound, "You have not supplied a valid email")
}
data := SendEmail{
RecipientEmail: email,
RecipientName: email,
SenderEmail: “test#test”,
SenderName: “name”,
Subject: "Reset Password",
PlainTextContent: "Here is your code to reset your password, if you did not request this email then please ignore.",
}
// error here
req, err := http.NewRequest("POST", "127.0.0.1:8081/", json.Marshal(data))
if err != nil {
fmt.Println(err)
}
defer req.Body.Close()
return c.JSON(http.StatusOK, email)
}
server 2:
e.GET("/", defaultRoute)
func defaultRoute(c echo.Context) (err error) {
u := SendEmail{}
if err = c.Bind(u); err != nil {
return
}
return c.JSON(http.StatusOK, u)
}
It's always nice to meet a Gopher. A few things you might want to know, Go supports multi-value returns in that a function can return more than one value.
byteInfo, err := json.Marshal(data) // has two values returned
// check if there was an error returned first
if err != nil{
// handle your error here
}
Now the line below in your code
// error here
req, err := http.NewRequest("POST", "127.0.0.1:8081/", json.Marshal(data))
Will become this
// error here
req, err := http.NewRequest("POST", "127.0.0.1:8081/", bytes.NewBuffer(byteInfo))
And you can continue with the rest of your code. Happy Coding!
json.Marshal returns []byte and error which means you're passing 4 values to http.NewRequest.
You should call json.Marshal first and then use the result for http.NewRequest.
body, err := json.Marshal(data)
if err != nil {
// deal with error
}
req, err := http.NewRequest("POST", "127.0.0.1:8081/", body)

How to properly read errors from golang oauth2

token, err := googleOauthConfig.Exchange(context.Background(), code)
if err != nil {
fmt.Fprintf(w, "Err: %+v", err)
}
The output of the fprintf is:
Err: oauth2: cannot fetch token: 401 Unauthorized
Response: {"error":"code_already_used","error_description":"code_already_used"}
I want to check if "error" = "code_already_used". For the life of me, I can't sort out how.
How do I check/return/read "error" or "error_description" of err?
I've looked at the oauth2 code and it's a bit above me.
// retrieveToken takes a *Config and uses that to retrieve an *internal.Token.
// This token is then mapped from *internal.Token into an *oauth2.Token which is returned along
// with an error..
func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) {
tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v)
if err != nil {
if rErr, ok := err.(*internal.RetrieveError); ok {
return nil, (*RetrieveError)(rErr)
}
return nil, err
}
return tokenFromInternal(tk), nil
}
How guess I'm trying to see the (*RetrieveError) part. Right?
THANK YOU!
The expression:
(*RetrieveError)(rErr)
converts therErr's type from *internal.RetrieveError to *RetrieveError. And since RetrieveError is declared in the oauth2 package, you can type assert the error you receive to *oauth2.RetrieveError to get the details. The details are contained in that type's Body field as a slice of bytes.
Since a slice of bytes is not the best format to be inspected and in your case it seems like the bytes contain a json object you can make your life easier by predefining a type into which you can unmarshal those details.
That is:
type ErrorDetails struct {
Error string `json:"error"`
ErrorDescription string `json:"error_description"`
}
token, err := googleOauthConfig.Exchange(context.Background(), code)
if err != nil {
fmt.Fprintf(w, "Err: %+v", err)
if rErr, ok := err.(*oauth2.RetrieveError); ok {
details := new(ErrorDetails)
if err := json.Unmarshal(rErr.Body, details); err != nil {
panic(err)
}
fmt.Println(details.Error, details.ErrorDescription)
}
}
Can do like this.
arr := strings.Split(err.Error(), "\n")
str := strings.Replace(arr[1], "Response: ", "", 1)
var details ErrorDetails
var json = jsoniter.ConfigCompatibleWithStandardLibrary
err := json.Unmarshal([]byte(str), &details)
if err == nil {
beego.Debug(details.Error)
beego.Debug(details.ErrorDescription)
}

How to turn DataBase access into a Function idiomatically in Go

I have built a Backend API in Go, it works however I want refactor the code for the DB access layer into a function - idiomatically.
// Get the form data entered by client; FirstName, LastName, phone Number,
// assign the person a unique i.d
// check to see if that user isn't in the database already
// if they are send an error message with the a 'bad' response code
// if they aren't in db add to db and send a message with success
func CreateStudentAccountEndpoint(response http.ResponseWriter, request *http.Request){
client, err := mongo.NewClient("mongodb://localhost:27017")
if err != nil {
log.Fatalf("Error connecting to mongoDB client Host: Err-> %v\n ", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
err = client.Connect(ctx)
if err != nil {
log.Fatalf("Error Connecting to MongoDB at context.WtihTimeout: Err-> %v\n ", err)
}
response.Header().Set("Content-Type", "application/json")
studentCollection := client.Database(dbName).Collection("students")
_, err = studentCollection.InsertOne(context.Background(),data)
if err != nil {
response.WriteHeader(501)
response.Write([]byte(`{ "message": "` + err.Error() + `" }`))
}
// encoding json object for returning to the client
jsonStudent, err := json.Marshal(student)
if err != nil {
http.Error(response, err.Error(), http.StatusInternalServerError)
}
response.Write(jsonStudent)
}
I understand that I can create a method which returns (*mongoClient, err) as I utilise the client local variable later on in the code.
However I am lost as to how to implement the defer cancel() part because it executes once the method CreateStudenAccountEndpoint is at the end. But I am at a loss on how to implement this defer section in a method that will recognise that I want the defer to happen at the end of the function that calls the DB access layer method e.g CreateStudentAccountEndpoint not the actual db access method itself.
As I understand it, the connection should be long-lived and set up as a part of a constructor, i.e. not part of the request flow.
This will typically look something like this:
type BackendAPI struct {
client *mongo.Client
}
func NewBackendAPI(mongoURI string) (*BackendAPI, error) {
client, err := mongo.NewClient(mongoURI)
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
err = client.Connect(ctx)
if err != nil {
return nil, err
}
return &BackendAPI{client}, nil
}
func (api *BackendAPI) func CreateStudentAccountEndpoint(response http.ResponseWriter, request *http.Request) {
response.Header().Set("Content-Type", "application/json")
// note the use of the long-lived api.client, which is connected already.
studentCollection := api.client.Database(dbName).Collection("students")
_, err = studentCollection.InsertOne(context.Background() ,data)
if err != nil {
response.WriteHeader(501)
response.Write([]byte(`{ "message": "` + err.Error() + `" }`))
return // at this point, the method should return
}
// encoding json object for returning to the client
jsonStudent, err := json.Marshal(student)
if err != nil {
http.Error(response, err.Error(), http.StatusInternalServerError)
}
response.Write(jsonStudent)
}
If you worry about losing the connection, you could implement a call to api.client.Ping in there, but in my opinion this should only be attempted if you encounter a failure you believe you can recover from by reconnecting.

Golang server "write tcp ... use of closed network connection"

I am beginner at Go, I had wrote small server to testing and deploy it on heroku platform. I have /logout request, which almost works, but sometimes I see something like this:
PANIC: write tcp 172.17.110.94:36641->10.11.189.195:9951: use of closed network connection
I don't know why it happens, and why sometimes it works perfectly.
My steps:
I send 1st POST request to /token-auth with body then generate token and send as response.
At 2nd I do /logout GET request with that token, and set token to Redis store
Here is full code of my redil_cli.go
package store
import (
"github.com/garyburd/redigo/redis"
)
type RedisCli struct {
conn redis.Conn
}
var instanceRedisCli *RedisCli = nil
func Connect() (conn *RedisCli) {
if instanceRedisCli == nil {
instanceRedisCli = new(RedisCli)
var err error
//this is works!!!
instanceRedisCli.conn, err = redis.Dial("tcp", "lab.redistogo.com:9951")
if err != nil {
panic(err)
}
if _, err := instanceRedisCli.conn.Do("AUTH", "password"); err != nil {
//instanceRedisCli.conn.Close()
panic(err)
}
}
return instanceRedisCli
}
func (redisCli *RedisCli) SetValue(key, value string, expiration ...interface{}) error {
_, err := redisCli.conn.Do("SET", key, value)
if err == nil && expiration != nil {
redisCli.conn.Do("EXPIRE", key, expiration[0])
}
return err
}
func (redisCli *RedisCli) GetValue(key string) (interface{}, error) {
data, err := redisCli.conn.Do("GET", key)
if err != nil{
panic(err)
}
return data, err
}
After that my function that checks Authorization header will panic while trying to do GetValue(key string) method
func (redisCli *RedisCli) GetValue(key string) (interface{}, error) {
data, err := redisCli.conn.Do("GET", key)
if err != nil{
panic(err)
}
return data, err
}
Can anyone point me, what I doing wrong?

Resources