web development – Golang / React Webapp Architecture

A project is structured as so:

A build server listens to changes in two repositories: a frontend and backend repo. When it picks up a change it builds, tests, and deploys the updates to a production server that exposes a publicly accessible endpoint.

On the production server the backend is a Golang https server that serves static files and then has a designated endpoint handling CRUD interactions with the database via REST api. The frontend is split between a static react app built and updated by the build server that reads dynamic content from the backend a REST api and then a similarity static authenticated CMS interface to manage the content itself.

Is this an solid or terrible way to structure a non-commercial webapp? Are there any obvious weaknesses I’m overlooking (besides pushing from build to production automatically)?

http – How would i rate limit a get request in golang?

I need some help with some code that i am working with; I want to rate limit the amount of request i send to 4 per minute.

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

var (
    vtAPIKey       = "some_api_key"
    systemFileHash = "some_hash"
)

func main() {
    hashAPIendpoint := fmt.Sprint("https://www.virustotal.com/vtapi/v2/file/report?apikey=", vtAPIKey, "&resource=", systemFileHash)
    // ping the api endpoint
    resp, err := http.Get(hashAPIendpoint)
    // log any errors
    if err != nil {
        log.Println(err)
    }
    // read the api response
    body, err := ioutil.ReadAll(resp.Body)
    // log all the errors
    if err != nil {
        log.Println(err)
    }
    // log everything
    log.Println(string(body))
}

web development – Golang backend architecture

I’m pretty new to web development and golang. I read a lot about http server development.

What is hard to understand being a newcomer is what’s the architecture should be in general – kind of how should it look like to be able to handler http requests, api requests, static and dynamic pages, authentication and authorisation, security etc.

It seems for me that there should be some awesome books. Can you please advise me?

go – Cookie authorization Golang

I’m writing login system in Go(Golang) using cookies.I think it’s isn’t safe enough. Can you provide some suggestions on how to improve the security.
Main file:

package main

import (
    "fmt"
    "golang.org/x/crypto/bcrypt"
    "html/template"
    "math/rand"
    "net/http"
    "strings"
    "time"
)

func init()  {
    rand.Seed(time.Now().Unix())
}

type User struct {
    Login, Email string
}

var (
    runes  = ()rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890")
)

func genToken() string {
    s := make(()rune, 15)
    for i := range s {
        s(i) = runes(rand.Intn(len(runes)))
    }
    return string(s)
}


func setCookie(w http.ResponseWriter, name, value string,d int) {
    cookie := http.Cookie{
        Name:    name,
        Value:   value,
    }
    if d != 0{
        expires := time.Now().AddDate(0,0,d)
        cookie.Expires = expires
    }
    http.SetCookie(w, &cookie)
}

func getCookie(r *http.Request, name string) string {
    c, err := r.Cookie(name)
    if err != nil {
        return ""
    }
    return c.Value
}

func deleteCookie(w http.ResponseWriter,name string){
    cookie := http.Cookie{
        Name: name,
        MaxAge: -1,
    }
    http.SetCookie(w, &cookie)
}

func signup(w http.ResponseWriter, r *http.Request) {
    if r.Method == "GET"{
        t, err := template.ParseFiles("signup.html")
        if err != nil{
            http.Error(w,"Internal server error",500)
        }
        t.Execute(w,nil)
    } else if r.Method == "POST"{
        r.ParseForm()
        data := r.Form
        var error string
        if data("login")(0) == ""{
            error = "Login can't be empty"
        } else if data("email")(0) == ""{
            error = "Email can't be empty"
        } else if data("password")(0) == ""{
            error = "Password cant't be empty"
        } else if len(data("login")(0)) < 4{
            error = "Login must be at least 4 characters"
        } else if DB.checkLogin(data("login")(0)){
            error = "User with such login already exists"
        } else if !strings.ContainsRune(data("email")(0),'@'){
            error = "Email must contain @"
        } else if DB.checkEmail(data("email")(0)) {
            error = "User with such email already exists"
        } else if len(data("password")(0)) < 8{
            error = "Password must be at least 8 characters"
        } else if data("password2")(0) != data("password")(0){
            error = "Passwords don't match"
        }
        if error != ""{
            values :=&User{}
            values.Login = data("login")(0)
            values.Email = data("email")(0)
            t, err := template.ParseFiles("signup.html")
            if err != nil{
                http.Error(w,"Internal server error",500)
            }
            t.Execute(w,values)
            fmt.Fprintln(w,"<hr><span style='color:red;'>" + error + "</span>")
        } else {
            hashedPassword, err := bcrypt.GenerateFromPassword(()byte(data("password")(0)),10)
            if err != nil{
                http.Error(w,"Internal server error",500)
            }
            DB.newUser(data("login")(0),data("email")(0),string(hashedPassword))
            http.Redirect(w,r,"/login",http.StatusSeeOther)
        }
    }

}

func signin(w http.ResponseWriter, r *http.Request) {

    if r.Method == "GET"{
        t, err := template.ParseFiles("signin.html")
        if err != nil{
            http.Error(w,"Internal server error",http.StatusInternalServerError)
        }

        t.Execute(w,nil)
    } else if r.Method == "POST" {
        r.ParseForm()
        data := r.Form
        var error string
        if !DB.checkLogin(data("login")(0)){
            error = "User with such login doesn't exists"
        } else {
            if !DB.checkPassword(data("login")(0),data("password")(0)){
                error = "Wrong password"
            }
        }
        if error != ""{
            values :=&User{}
            values.Login = data("login")(0)
            t, err := template.ParseFiles("signin.html")
            if err != nil{
                http.Error(w,"Internal server error",http.StatusInternalServerError)
            }
            t.Execute(w,values)
            fmt.Fprintln(w,"<hr><span style='color:red;'>" + error + "</span>")
        } else {
            expiresAfter := 0
            if r.FormValue("remember") == "1"{
                expiresAfter = 30
            }
            token := genToken()
            setCookie(w,"login",data("login")(0),expiresAfter)
            setCookie(w,"session_token",token,expiresAfter)
            DB.setToken(token,data("login")(0))
            http.Redirect(w,r,"/",http.StatusSeeOther)
        }
    }
}

func mainPage(w http.ResponseWriter, r *http.Request) {
    login := getCookie(r,"login")
    if !DB.checkLogin(login){

    }
    token := getCookie(r,"session_token")
    if !DB.checkToken(login,token){
        http.Redirect(w,r,"/login",http.StatusSeeOther)
    }
    t, err := template.ParseFiles("main.html")
    if err != nil{
        http.Error(w,"Internal server error",http.StatusInternalServerError)
    }
    user := DB.getUser(login)
    t.Execute(w, user)
}

func logout(w http.ResponseWriter,r *http.Request){
    login := getCookie(r,"login")
    deleteCookie(w,"login")
    deleteCookie(w,"token")
    DB.setToken("",login)
    http.Redirect(w,r,"/login",http.StatusSeeOther)
}

func main() {
    http.HandleFunc("/register", signup)
    http.HandleFunc("/login", signin)
    http.HandleFunc("/", mainPage)
    http.HandleFunc("/logout",logout)
    http.ListenAndServe(":8080", nil)
}

Database file:

package main

import (
    "database/sql"
    "golang.org/x/crypto/bcrypt"
    "log"

    _ "github.com/go-sql-driver/mysql"
)

var DB = newDB("root:root574@/users")

type db struct {
    DB *sql.DB
}

func newDB(name string) *db {
    conn, err := sql.Open("mysql", name)
    if err != nil {
        log.Fatal(err)
    }
    if err = conn.Ping(); err != nil {
        log.Fatal(err)
    }
    return &db{DB: conn}
}

func (db db) newUser(login, email, password string) {
    db.DB.Exec("INSERT INTO users(login,email,password) VALUES (?,?,?)", login, email, password)
}

func (db db) setToken(token, login string) {
    db.DB.Exec("UPDATE users SET token = ? WHERE login = ?",token,login)
}

func (db db) checkLogin(login string) bool {
    var rows, _ = db.DB.Query("SELECT id FROM users WHERE login = ?", login)
    if rows.Next() {
        return true
    }
    rows.Close()
    return false
}

func (db db) checkEmail(email string) bool {
    var rows, _ = db.DB.Query("SELECT id FROM users WHERE email = ?", email)
    if rows.Next() {
        return true
    }
    rows.Close()
    return false
}

func (db db) checkPassword(login, password string) bool{
    var rows, _ = db.DB.Query("SELECT password FROM users WHERE login = ?", login)
    var dbpassword string
    rows.Next()
    rows.Scan(&dbpassword)
    rows.Close()
    if bcrypt.CompareHashAndPassword(()byte(dbpassword),()byte(password)) != nil{
        return false
    }
    return true
}

func (db db) checkToken(login, token string) bool {
    var rows, _ = db.DB.Query("SELECT token FROM users WHERE login = ?",login)
    var dbtoken string
    if rows.Next(){
        rows.Scan(&dbtoken)
        if token == dbtoken{
            return true
        }
    }
    rows.Close()
    return false
}

func (db db) getUser(login string) *User {
    var rows, _ = db.DB.Query("select email FROM users WHERE login = ?",login)
    user := &User{}
    rows.Next()
    rows.Scan(&user.Email)
    rows.Close()
    user.Login = login
    return user
}

how to generate bech32/segwit address from pubkey in golang

I am trying to generate bech32/segwit address in golang with the following code:

var pubkey *btcec.PubKey
address, err := btcutil.NewAddressPubKey(pubkey.SerializeCompressed(), chainParams)
if err != nil {
    log.Fatal(err)
}
address.SetFormat(btcutil.PKFCompressed)
bech32Bytes, err := bech32.ConvertBits(address.ScriptAddress(), 8, 5, true)
if err != nil {
    log.Fatal(err)
}
segwitaddr, err := bech32.Encode("tb", bech32Bytes)
if err != nil {
    log.Fatal(err)
}

and also more simply

var e *hdkeychain.ExtendedKey
address, err := e.Address(chainParams)
bech32Bytes, err := bech32.ConvertBits(address.ScriptAddress(), 8, 5, true)
if err != nil {
    log.Fatal(err)
}
segwitaddr, err := bech32.Encode("tb", bech32Bytes)
if err != nil {
    log.Fatal(err)
}

But neither segwitaddr generated match the bip39 address I got from https://iancoleman.io/bip39/. What is wrong with the code above or how to properly get a bech32 address from a pub key?

I have looked into another post on the same question, but could not figure out how to prepare the data needed in golang. More specifically, I am confused in preparing the input ()byte call bech32.Encode() and using bech32.ConverBits().

golang – Ponteiros em Go

Estou tentando alterar uma String em Go usando ponteiros, porem eu recebo um

invalid operation: oculta(i) (type *string does not support indexing)

A função que estou realizando a alteração.

func verifica(palavra, chute string, oculta *string) {
    for i, l := range palavra {
        if string(l) == chute {
            *oculta(i) = chute
        } 
    }
}

go – What is the best practice to use multi different statement in Golang

After reading some of this book Building Maintainable Software
I am curious about how can I use a multi different statement like this to be more maintainable.

    if UserNotActive(){
        // do job 1
    }else if UserCanWriteSomeThing(){
        // do job 2
    }else if UserMessageIsSomeMessage(){
        // do job 3
    }else if TheTimeIsMidNight(){
        // do job 4
    }// and whatever

method names are fake, but my code is something like this and maybe they statements are more than 10 or 15

What is the best syntax for this code? Can I use Switch?

go – Clean code architecture in Golang

https://github.com/Abdukahhor/swe

Sample project in clean code (Golang).

Can you review the repo?

Is it done correctly ?

handlers: any transport layer http web api, grpc, graphql and etc.

app: Business layer

storage: Database and caches

services: external services


package main

import (
    "flag"
    "log"
    "net"
    "os"
    "os/signal"
    "syscall"

    "github.com/abdukahhor/swe/app"
    "github.com/abdukahhor/swe/handlers/rpc"
    "github.com/abdukahhor/swe/storage"
    "google.golang.org/grpc"
)

func main() {
    var (
        addr   = flag.String("addr", ":8087", "ip:port of server")
        dbpath = flag.String("db", "sdb", "Folder path of the embedded database")
    )

    flag.Parse()

    db, err := storage.Connect(*dbpath)
    if err != nil {
        log.Fatalln(err)
    }
    defer db.Close()

    l, err := net.Listen("tcp", *addr)
    if err != nil {
        log.Fatalln(err)
    }
    defer l.Close()

    s := grpc.NewServer()
    c := app.New(db)
    rpc.Register(s, c)

    go func() {
        sigint := make(chan os.Signal)
        signal.Notify(sigint, os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGINT)
        log.Println("server received signal ", <-sigint)

        s.GracefulStop()
        os.Exit(0)
    }()

    log.Println("server started at ", *addr)
    err = s.Serve(l)
    if err != nil {
        log.Fatalln(err)
    }
}
```

How to implement BTree + in Golang?

I have been reading about indexing techniques and most of the tools implemented BTrees. While I don't know BTree + yet, I'm not having any problems either, but I was looking for alternatives, mainly because I couldn't find how BTree + renders when stored in a disk file.

The scenario is that my indexing class, let's say MyIndexer it has different methods for different data formats (CSV, JSON, etc.) with corresponding methods indexCSV(), indexJSON(). Now once indexing is done how do I save to file, serialize data, JSON or what and load it again?

Thank you,

network – Golang: Strange delays when making an HTTP tunnel through the network.

Server code: https://play.golang.org/p/tMF8uRmNMQG

Client code: https://play.golang.org/p/GepYizWNeIH

The code above assumes that a local HTTP server listens on port 8080.

When I try to issue a GET request to http: // localhost: 1234, the tunnel seems to stop after the GET passes (I can see this happening at tee exit).

Then, in the case of a local http.py server python3 -m, the server responds after a moment. This answer does not reach the browser (again, I can see the answer on tee output).

When trying this with a public site (I used textfiles.com to test) the responses are also slow. In one of my previous tests, I calculated the interval between responses to be about 5 seconds.

However, when you bind a netcat listener to localhost and use the tunnel to connect, there is no delay and all data goes from the server to the client almost instantly.

Does this have something to do with setting the TCP PSH flag? Why five seconds (is it maintenance time)? I am lost for what is different in these two situations.