How do I change the import file? - go

I have the following function in golang:
import (
"github.com/aws/aws-sdk-go/service/iam"
"github.com/aws/aws-sdk-go/aws/session"
"fmt"
)
func NewIAM() *SphinxIAM {
// awsConfig := aws.NewConfig()
sess, err := session.NewSession()
if err != nil {
fmt.Println("Failed to create session,", err)
return nil
}
session := &SphinxIAM{iam: iam.New(sess)}
return session
}
Now, I am getting the following error when I run this:
cannot use sess (type *session.Session) as type "github.com/aws/aws-sdk-go/aws/client".ConfigProvider in argument to iam.New:
*session.Session does not implement "github.com/aws/aws-sdk-go/aws/client".ConfigProvider (wrong type for ClientConfig method)
have ClientConfig(string, ...*"stash/cloud/sphinx/vendor/github.com/aws/aws-sdk-go/aws".Config) "stash/cloud/sphinx/vendor/github.com/aws/aws-sdk-go/aws/client".Config
want ClientConfig(string, ...*"github.com/aws/aws-sdk-go/aws".Config) "github.com/aws/aws-sdk-go/aws/client".Config
I have to change the method getting imported but how do I exactly do that?
Thanks!

The problem here is that your github.com/aws/aws-sdk-go/aws/session package is vendored, it is loaded from the folder stash/cloud/sphinx/vendor/github.com/aws/aws-sdk-go/aws.
But the function you want to pass it: iam.New() is not vendored, it does not come from the same vendor folder (stash/cloud/sphinx/vendor/xxx) but it comes directly from github.com/aws/aws-sdk-go/service/iam.
Either put both packages under the same vendor folder, or none. It is possible that one of your dependency tool does this, (e.g. glide), in which case you should instruct your tool to handle both as vendored.

Related

how to create a context object in google cloud run for firebase

I'm trying to create a context object, so that I can connect to firestore from cloud run, however, all the examples I find on the net basically say I need a context objects, examples I find online usually look like this:
ctx := context.Background()
client, err := firestore.NewClient(ctx, "projectID")
if err != nil {
fail(w, err.Error())
// TODO: Handle error.
}
You can find these examples in places like this one:
https://godoc.org/cloud.google.com/go/firestore#example-NewClient
Nowhere in this example is there an explanation of where to find the context object.
so I just get this error:
undefined: context
I think the documentation is just too confusing.
You should use r.Context() of http.Request object in the request handler instead of initializing a new detached context like context.Background().
The main purpose of contexts is to propagate them, and in Cloud Run you always process requests, so if you pass the request’s context, it’s the right thing to do.
I think in your case, “context” package is not imported. Make sure to use go 1.11+ in your Dockerfile and say:
import “context”
In Go, you need to import packages. For this statement ctx := context.Background() add to the top of your source file import "context" or merge with your existing import set.
Like most languages, the more experience you have the more the language makes sense and you just know what to do. Most languages are the same. In C/C++ you have the include statement, C# the using statement, in Python the import statement, etc.
Google has a large package of examples for using Go and Google Cloud Platform:
Google Cloud Examples in Go
I wrote an article that documents my 30-day journey to learn Go and Google Cloud Platform.
Google Cloud and Go – My Journey to Learn a new Language in 30 days
Given the plethora of 3 lines of code examples that are hard for beginners, and the lack of complete working examples online, like myself, here is a full working example, which is kinda what I needed when I started this task, I hope this helps anybody in the future.
package main
import (
"cloud.google.com/go/firestore" // https://godoc.org/cloud.google.com/go/firestore"
"context" // https://blog.golang.org/context
firebase "firebase.google.com/go"
"fmt"
"log"
"net/http"
"os"
)
func fail(w http.ResponseWriter, msg string) {
fmt.Fprintln(w, "fail:"+msg)
log.Println("fail:" + msg)
}
// State example code
type State struct {
Capital string `firestore:"capital"`
Population float64 `firestore:"pop"` // in millions
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
override := make(map[string]interface{})
ctx := context.Background()
client, err := firestore.NewClient(ctx, "YOURPID")// set GOOGLE_APPLICATION_CREDENTIALS env var
if err != nil {
fail(w, err.Error())
return
}
states := client.Collection("States")
ny := states.Doc("NewYork")
wr, err := ny.Create(ctx, State{
Capital: "Albany",
Population: 19.8,
})
fmt.Println(wr)
})
log.Fatal(http.ListenAndServe("0.0.0.0:8082", nil))
}

How do you securely serve a file in golang

I'm new to developing web applications. I'm working with golang and would like to serve user uploaded files securely, such as allowing them to view their own files only.
Now I have saved those files to a local file system with random names. If I serve the entire directory, malicious users may view other users files. This sounds like a common use case, I wonder what's the best approach to deal with it?
This question in pretty vague and architectural decisions must be made to optimize data access and secure the files.
However, here is a simple solution that might serve your use-case.
package main
import (
"fmt"
"mime"
"net/http"
"path/filepath"
)
//UserFilesMap is the map that contains
var UserFilesMap map[string]FilePermission
type FilePermission map[string]struct{}
//FileServer is the function that serves files
func FileServer(w http.ResponseWriter, r *http.Request) {
//get the file path the user wants to access
filename := r.URL.Path[9:]
var uname, pass string
var ok bool
if uname, pass, ok = r.BasicAuth(); !ok {
w.WriteHeader(http.StatusForbidden)
return
}
if !(uname == "user" && pass == "1234") {
w.WriteHeader(http.StatusForbidden)
return
}
//Checking if user has permission to the file
if _, ok := UserFilesMap[uname][filename]; !ok {
w.WriteHeader(http.StatusForbidden)
return
}
w.Header().Set("Content-Type", mime.TypeByExtension(filepath.Ext(filename)))
http.ServeFile(w, r, "files/"+filename)
}
func main() {
UserFilesMap = make(map[string]FilePermission)
// UserFilesMap["user"] = FilePermission{"xyz.txt": struct{}{}}
UserFilesMap["user"] = FilePermission{"abc.txt": struct{}{}}
http.HandleFunc("/getFile/", FileServer)
if err := http.ListenAndServe(":8080", nil); err != nil {
fmt.Println("Error in ListenAndServe")
}
}
Here, I used a map to store the permissions of files. I would suggest you go for a SQL table instead.
If ur filenames are random and long enough and use a secure random generator this is already secure (unless directory-listing is enabled) with some limits though.
https://golang.org/pkg/crypto/rand/
One user will have access to the file only if he has the url with the random name. The limitation is though that the URL will be saved in the browser history, if someone else finds it he will also have access to it.

How to make templates work with gin framework?

I am newbie to golang.
To learn it I have started with a simple web app using gin framework.
I have followed the gin doc & configured template file but not able to make it work. I am getting an error -
panic: html/template: pattern matches no files: `templates/*`
goroutine 1 [running]:
html/template.Must
/usr/local/Cellar/go/1.5.2/libexec/src/html/template/template.go:330
github.com/gin-gonic/gin.(*Engine).LoadHTMLGlob
/Users/ameypatil/deployment/go/src/github.com/gin-gonic/gin/gin.go:126
main.main()
/Users/ameypatil/deployment/go/src/github.com/ameykpatil/gospike/main.go:17
Below is my code -
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
//os.Setenv("GIN_MODE", "release")
//gin.SetMode(gin.ReleaseMode)
// Creates a gin router with default middleware:
// logger and recovery (crash-free) middleware
router := gin.Default()
router.LoadHTMLGlob("templates/*")
//router.LoadHTMLFiles("templates/index.tmpl")
router.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.tmpl", gin.H{
"title": "GoSpike",
})
})
// By default it serves on :8080 unless a
// PORT environment variable was defined.
router.Run(":4848")
}
My directory structure is
- gospike
--- templates
------index.tmpl
--- main.go
go install command does not give any error
but on actually running, it gives the above error. I searched & there were similar issues logged on gin's github repo but they are closed now.
I have tried various things but I guess I am missing something obvious. What am I missing?
I'm guessing the issue is that you're using a relative filepath to access your templates.
If I compile and run your code from the gospike directory, it works fine. But if I run gospike from any other directory, I get the same error you were seeing.
So either you need to always run gospike in the parent directory of templates, or you need to use the absolute path. You could either hard code it:
router.LoadHTMLGlob("/go/src/github.com/ameykpatil/gospike/templates/*")
or you could do something like
router.LoadHTMLGlob(filepath.Join(os.Getenv("GOPATH"),
"src/github.com/ameykpatil/gospike/templates/*"))
but that will fail if you have multiple paths set in your GOPATH. A better long-term solution might be setting a special environment variable like TMPL_DIR, and then just using that:
router.LoadHTMLGlob(filepath.Join(os.Getenv("TMPL_DIR"), "*"))
use relative path glob will working, you can try to code
router.LoadHTMLGlob("./templates/*")
notice the . dot sign which meaning current directory, gin.Engine will load template
base on templates subdirectory of current directory .
Here is how I do it. This walks through the directory and collects the files marked with my template suffix which is .html & then I just include all of those. I haven't seen this answer anywhere so I thought Id post it.
// START UP THE ROUTER
router := gin.Default()
var files []string
filepath.Walk("./views", func(path string, info os.FileInfo, err error) error {
if strings.HasSuffix(path, ".html") {
files = append(files, path)
}
return nil
})
router.LoadHTMLFiles(files...)
// SERVE STATICS
router.Use(static.Serve("/css", static.LocalFile("./css", true)))
router.Use(static.Serve("/js", static.LocalFile("./js", true)))
router.Use(static.Serve("/images", static.LocalFile("./images", true)))
routers.LoadBaseRoutes(router)
routers.LoadBlog(router)
router.Run(":8080")
There is a multitemplate HTML render to support multi tempaltes.
You can use AddFromFiles to add multi files:
r.AddFromFiles("index", "templates/base.html", "templates/index.html")
r.AddFromFiles("article", "templates/base.html", "templates/index.html", "templates/article.html")
Or load multi files under a directory:
package main
import (
"path/filepath"
"github.com/gin-contrib/multitemplate"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.New()
r.HTMLRender = loadTemplates()
// ...
}
func loadTemplates() multitemplate.Render {
files, err := filepath.Glob("template/*.tmpl")
if err != nil {
panic("failed to load html templates: " + err.Error())
}
r := multitemplate.New()
// Generate our templates map from our template/ directories
for _, file := range files {
r.AddFromFiles(filepath.Base(file), file)
}
// add other html templates directly
r.Add("test.tmpl", someTemplate)
return r
}
You could see more APIs in this repo you want, hope this post help :)

Google Cloud Bigtable authentication with Go

I'm trying to insert a simple record as in GoDoc. But this returns,
rpc error: code = 7 desc = "User can't access project: tidy-groove"
When I searched for grpc codes, it says..
PermissionDenied Code = 7
// Unauthenticated indicates the request does not have valid
// authentication credentials for the operation.
I've enabled Big table in my console and created a cluster and a service account and recieved the json. What I'm doing wrong here?
package main
import (
"fmt"
"golang.org/x/net/context"
"golang.org/x/oauth2/google"
"google.golang.org/cloud"
"google.golang.org/cloud/bigtable"
"io/ioutil"
)
func main() {
fmt.Println("Start!")
put()
}
func getClient() *bigtable.Client {
jsonKey, err := ioutil.ReadFile("TestProject-7854ea9op741.json")
if err != nil {
fmt.Println(err.Error())
}
config, err := google.JWTConfigFromJSON(
jsonKey,
bigtable.Scope,
) // or bigtable.AdminScope, etc.
if err != nil {
fmt.Println(err.Error())
}
ctx := context.Background()
client, err := bigtable.NewClient(ctx, "tidy-groove", "asia-east1-b", "test1-bigtable", cloud.WithTokenSource(config.TokenSource(ctx)))
if err != nil {
fmt.Println(err.Error())
}
return client
}
func put() {
ctx := context.Background()
client := getClient()
tbl := client.Open("table1")
mut := bigtable.NewMutation()
mut.Set("links", "maps.google.com", bigtable.Now(), []byte("1"))
mut.Set("links", "golang.org", bigtable.Now(), []byte("1"))
err := tbl.Apply(ctx, "com.google.cloud", mut)
if err != nil {
fmt.Println(err.Error())
}
}
I've solved the problem. It's nothing wrong with the code, but config json itself. So anyone who out there want to authenticate and came here by google search... This code is correct and working perfectly. What I've done wrong is follows.
First I made a service account and got the json. But google warned me that im not an owner of project hence it wont be added to accept list but anyway it let me download the json.
Then I deleted that key from console and requested project owner to create a key for me.
There he has created another key with the same name I given.. And since he's the owner no error/warning msgs displayed and successfully json file was downloaded.
When I tried with that... my question begun. That's when i posted this question.
After that with no solutions. I asked owner to delete that key and create another key but with a different name..
Then it worked! It seems if you try to create a key with non-owner account and then again create with same name ( after deleting original of course ) has no effect. Hope this helps everyone out there :)
Take a look at: helloworld.go or search.go which uses GOOGLE_APPLICATION_CREDENTIALS environment variable.
For most environments, you no longer even need to set GOOGLE_APPLICATION_CREDENTIALS. Google Cloud Platform, Managed VMs or Google App Engine all have the right thing set for you. Your desktop environment will also be correct if you've used gcloud init or it's predecessor gcloud auth login followed by gcloud config set project <projectID>.

How to store and get a pointer reference in a global scope in GO

I have got the follow code:
package main
func main() {
// create a pointer referece of session of Mongo DB
session := mongoDB.CreateSession()
// Question 1 : How to store a pointer reference in a global scope and using anywhere of the code
defer session.Close()
// Note I suppose that the code call to handler methods that call to the Process in the package controller(the last one code)
}
Code of creating a session of MongoDB
package mongoDB
func CreateSession() *mgo.Session {
session, err := mgo.Dial("192.168.0.108:27017/databasename")
if err != nil {
panic(err)
}
session.SetMode(mgo.Monotonic, true)
return session
}
Place where I want to use the pointer reference that was store in the main
package controller
func Process() {
// Question 2 : How can a get the pointer reference store in Question 1 if is posible
collection := mongoDB.CreateCollection(session, "namedatabase", "colectionData")
mongoDB.InsertData(collection, "Ale", "45646565")
}
The idea is to avoid passing by reference session(my pointer reference in the main function) in every one of the functions created for all the project.
You can't have your controller package import main. That is not a good idea (and I am quite sure it is not even possible). But that doesn't mean you can't have a global session variable in the controller.
You can try this:
package main
import (
"controller"
"mongoDB"
)
func main() {
// create a pointer referece of session of Mongo DB
session := mongoDB.CreateSession()
defer session.Close()
controller.SetDBSession(session) // Or controller.Init or whatever you like
controller.Process()
}
And then in the controller package you have:
package controller
import "mongoDB"
// Global session var for the package
var session mongoDB.Session
// SetDBSession sets the mongoDB session to be used by the controller package.
// This function must be called before calling Process()
func SetDBSession(s mongoDB.Session) {
session = s
}
func Process() {
collection := mongoDB.CreateCollection(session, "namedatabase", "colectionData")
mongoDB.InsertData(collection, "Ale", "45646565")
}
Using this solution, you will only have to pass the session to the controller package once, letting main take care of the creating and closing of the session.

Resources