Fresh restructuring of project. Now with cmd, internal, and bin folder
Should be good for future microservices and such Signed-off-by: Ethan Wellenreiter <ewellenreiter@gmail.com>
This commit is contained in:
parent
7eb459220a
commit
aa1b8d1d1b
52
backend/.air.toml
Normal file
52
backend/.air.toml
Normal file
@ -0,0 +1,52 @@
|
||||
root = "."
|
||||
testdata_dir = "testdata"
|
||||
tmp_dir = "bin"
|
||||
|
||||
[build]
|
||||
args_bin = []
|
||||
bin = "./bin/main.exe"
|
||||
cmd = "go build -o ./bin/main.exe ./cmd/api"
|
||||
delay = 1000
|
||||
exclude_dir = ["assets", "bin", "vendor", "testdata", "docs", "scripts"]
|
||||
exclude_file = []
|
||||
exclude_regex = ["_test.go"]
|
||||
exclude_unchanged = false
|
||||
follow_symlink = false
|
||||
full_bin = ""
|
||||
include_dir = []
|
||||
include_ext = ["go", "tpl", "tmpl", "html"]
|
||||
include_file = []
|
||||
kill_delay = "0s"
|
||||
log = "build-errors.log"
|
||||
poll = false
|
||||
poll_interval = 0
|
||||
post_cmd = []
|
||||
pre_cmd = []
|
||||
rerun = false
|
||||
rerun_delay = 500
|
||||
send_interrupt = false
|
||||
stop_on_error = false
|
||||
|
||||
[color]
|
||||
app = ""
|
||||
build = "yellow"
|
||||
main = "magenta"
|
||||
runner = "green"
|
||||
watcher = "cyan"
|
||||
|
||||
[log]
|
||||
main_only = false
|
||||
silent = false
|
||||
time = false
|
||||
|
||||
[misc]
|
||||
clean_on_exit = false
|
||||
|
||||
[proxy]
|
||||
app_port = 0
|
||||
enabled = false
|
||||
proxy_port = 0
|
||||
|
||||
[screen]
|
||||
clear_on_rebuild = false
|
||||
keep_scroll = true
|
||||
1
backend/bin/build-errors.log
Normal file
1
backend/bin/build-errors.log
Normal file
@ -0,0 +1 @@
|
||||
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1
|
||||
BIN
backend/bin/main.exe
Normal file
BIN
backend/bin/main.exe
Normal file
Binary file not shown.
0
backend/cmd/api/anything_server_layer
Normal file
0
backend/cmd/api/anything_server_layer
Normal file
43
backend/cmd/api/api.go
Normal file
43
backend/cmd/api/api.go
Normal file
@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"git.ewellenr.ca/receipt_indexer/backend/internal/auth"
|
||||
)
|
||||
|
||||
type application struct {
|
||||
// set up the configs stuff here
|
||||
config config
|
||||
auth auth.Authenticator
|
||||
}
|
||||
|
||||
type config struct {
|
||||
addr string
|
||||
// holds the different stuff like rate limiter, store, authenticator
|
||||
}
|
||||
|
||||
func (app *application) mount() *http.ServeMux {
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.HandleFunc("GET /v1/health", app.healthCheckHandler)
|
||||
|
||||
return mux
|
||||
}
|
||||
|
||||
func (app *application) run(mux http.Handler) error {
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: app.config.addr,
|
||||
Handler: mux,
|
||||
WriteTimeout: time.Second * 30, // if the server takes this much time to read or write, time it out.
|
||||
ReadTimeout: time.Second * 10,
|
||||
IdleTimeout: time.Minute,
|
||||
}
|
||||
|
||||
log.Printf("Server has started at %s", app.config.addr) // temporary
|
||||
|
||||
return srv.ListenAndServe()
|
||||
}
|
||||
8
backend/cmd/api/health.go
Normal file
8
backend/cmd/api/health.go
Normal file
@ -0,0 +1,8 @@
|
||||
package main
|
||||
|
||||
import "net/http"
|
||||
|
||||
func (app *application) healthCheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("ok"))
|
||||
|
||||
}
|
||||
21
backend/cmd/api/main.go
Normal file
21
backend/cmd/api/main.go
Normal file
@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// set up the application config here
|
||||
|
||||
cfg := config{
|
||||
addr: ":8080",
|
||||
}
|
||||
|
||||
app := application{
|
||||
config: cfg,
|
||||
}
|
||||
|
||||
// fmt.Println(app)
|
||||
mux := app.mount()
|
||||
log.Fatal(app.run(mux))
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
module backend/app
|
||||
|
||||
go 1.24.2
|
||||
|
||||
require github.com/spf13/viper v1.20.1
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.12.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
@ -1,52 +0,0 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
|
||||
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
|
||||
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
|
||||
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
|
||||
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@ -1,86 +0,0 @@
|
||||
package main
|
||||
|
||||
import ( // "ewellenr.ca/ewellenr/receipt_indexer/backend/signin"
|
||||
// "git.ewellenr.ca/ewellenr/receipt_indexer/backend/internal/signin"
|
||||
// "receipt_indexer/backend/internal/testing"
|
||||
|
||||
"backend/signin"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func setupConfig() {
|
||||
viper.SetConfigName("config")
|
||||
viper.SetConfigType("yaml")
|
||||
viper.AddConfigPath("..")
|
||||
viper.AddConfigPath(".")
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||
// Config file not found; ignore error if desired
|
||||
} else {
|
||||
// Config file was found but another error was produced
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// fmt.Println("hi")
|
||||
// params := signin.DefaultArgon2Params
|
||||
|
||||
// test, _ := params.GeneratePassEncoding("hello")
|
||||
// fmt.Println(test)
|
||||
|
||||
// fmt.Println(signin.CheckPasswordAgainstEncoding("hello", test))
|
||||
// fmt.Println(signin.CheckPasswordAgainstEncoding("hello1", test))
|
||||
|
||||
// authenticate.test2()
|
||||
setupConfig()
|
||||
|
||||
signin.InitializeSessionRedis(viper.GetStringMapString("redis"))
|
||||
}
|
||||
|
||||
// fmt.Println(viper.AllKeys())
|
||||
// redis := viper.GetStringMapString("redis")
|
||||
// fmt.Println(viper.Get("redis"))
|
||||
// fmt.Println(redis["address"])
|
||||
|
||||
// err := signin.InitializeRedis(viper.GetStringMapString("redis"))
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
|
||||
// cookie, _ := signin.Login("monkey")
|
||||
// fmt.Println(cookie)
|
||||
// valid, err := signin.ValidateSession(cookie)
|
||||
// fmt.Println(valid)
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
|
||||
// time.Sleep(time.Second * 10)
|
||||
// fmt.Println(cookie)
|
||||
// valid, err = signin.ValidateSession(cookie)
|
||||
// fmt.Println(valid)
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
|
||||
// // fmt.Println(rs)
|
||||
// // fmt.Println(map[string]int{"a": 1, "b": 2, "c": 3})
|
||||
|
||||
// ctx := context.Background()
|
||||
|
||||
// err := client.Set(ctx, "test", "bar", time.Second*30).Err()
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
|
||||
// val, err := client.Get(ctx, "foo").Result()
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// fmt.Println("foo", val)
|
||||
// signin.SetupSecurityAddresses()
|
||||
|
||||
// }
|
||||
@ -1,7 +0,0 @@
|
||||
go 1.24.2
|
||||
|
||||
use (
|
||||
./app
|
||||
./redis_helper
|
||||
./signin
|
||||
)
|
||||
@ -1,56 +0,0 @@
|
||||
cel.dev/expr v0.16.1/go.mod h1:AsGA5zb3WruAEQeQng1RZdGEXmBj0jvMWh6l5SnNuC8=
|
||||
cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U=
|
||||
cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8=
|
||||
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
||||
cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY=
|
||||
cloud.google.com/go/monitoring v1.21.2/go.mod h1:hS3pXvaG8KgWTSz+dAdyzPrGUYmi2Q+WFX8g2hqVEZU=
|
||||
cloud.google.com/go/storage v1.49.0/go.mod h1:k1eHhhpLvrPjVGfo0mOUPEJ4Y2+a/Hv5PiwehZI9qGU=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1/go.mod h1:jyqM3eLpJ3IbIFDTKVz2rF9T/xWGW0rIriGwnz8l9Tk=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1/go.mod h1:viRWSEhtMZqz1rhwmOVKkWl6SwmVowfL9O2YR5gI2PE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
|
||||
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/pkg/sftp v1.13.7/go.mod h1:KMKI0t3T6hfA+lTR/ssZdunHo+uwq7ghoN09/FSu3DY=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.29.0/go.mod h1:GW2aWZNwR2ZxDLdv8OyC2G8zkRoQBuURgV7RPQgcPoU=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
|
||||
go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
|
||||
go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
|
||||
go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ=
|
||||
go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
google.golang.org/api v0.215.0/go.mod h1:fta3CVtuJYOEdugLNWm6WodzOS8KdFckABwN4I40hzY=
|
||||
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
|
||||
google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s=
|
||||
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
@ -1,10 +0,0 @@
|
||||
module backend/redis_helper
|
||||
|
||||
go 1.24.2
|
||||
|
||||
require github.com/redis/go-redis/v9 v9.7.3
|
||||
|
||||
require (
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
)
|
||||
@ -1,10 +0,0 @@
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
||||
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
||||
@ -1,83 +0,0 @@
|
||||
package redis_helper
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidRedisPort = errors.New("Invalid Redis Port")
|
||||
ErrInvalidRedisDB = errors.New("Invalid Redis DB mode")
|
||||
ErrInvalidRedisProtocol = errors.New("Invalid Redis Protocol")
|
||||
ErrInvalidDatabaseIndex = errors.New("Invalid Redis Database Index")
|
||||
ErrClientNotYetSet = errors.New("Redis connection not set up")
|
||||
)
|
||||
|
||||
var defaultRedisSettings = redis.Options{
|
||||
Addr: "localhost:6379",
|
||||
Password: "",
|
||||
DB: 0,
|
||||
}
|
||||
|
||||
func ProcessSettingsMap(settings map[string]string) (options *redis.Options, err error) {
|
||||
temp := defaultRedisSettings
|
||||
options = &temp
|
||||
|
||||
for key, val := range settings {
|
||||
// fmt.Println(key, val)
|
||||
if val == "" {
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "host":
|
||||
// fmt.Println("entered")
|
||||
options.Addr = val + ":" + strings.Split(options.Addr, ":")[1]
|
||||
case "port":
|
||||
s, err := strconv.ParseUint(val, 10, 16)
|
||||
if s < 3000 || err != nil {
|
||||
return nil, ErrInvalidRedisPort
|
||||
}
|
||||
options.Addr = strings.Split(options.Addr, ":")[0] + ":" + val
|
||||
case "password":
|
||||
options.Password = val
|
||||
// case "db":
|
||||
// s, err := strconv.ParseUint(val, 10, 64)
|
||||
// if err != nil {
|
||||
// return ErrInvalidRedisDB
|
||||
// }
|
||||
// options.DB = s
|
||||
case "protocol":
|
||||
s, err := strconv.ParseInt(val, 10, 0)
|
||||
if err != nil {
|
||||
return nil, ErrInvalidRedisProtocol
|
||||
}
|
||||
options.Protocol = int(s)
|
||||
}
|
||||
}
|
||||
|
||||
return options, nil
|
||||
}
|
||||
|
||||
func SetDB(options *redis.Options, db int) error {
|
||||
if db < 0 { //|| db > 16 {
|
||||
return ErrInvalidDatabaseIndex
|
||||
}
|
||||
|
||||
options.DB = db
|
||||
return nil
|
||||
}
|
||||
|
||||
func InitializeRedis(options *redis.Options) (client *redis.Client, err error) {
|
||||
client = redis.NewClient(options)
|
||||
|
||||
err = client.Ping(context.Background()).Err()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
@ -1,128 +0,0 @@
|
||||
package signin
|
||||
|
||||
// credit to https://www.alexedwards.net/blog/how-to-hash-and-verify-passwords-with-argon2-in-go
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/argon2"
|
||||
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// PUBLIC METHODS AND STRUCTURES
|
||||
|
||||
// argon2 parameter struct
|
||||
type Argon2params struct {
|
||||
Memory uint32
|
||||
Iterations uint32
|
||||
Parallelism uint8
|
||||
SaltLength uint32
|
||||
KeyLength uint32
|
||||
}
|
||||
|
||||
var DefaultArgon2Params = &Argon2params{
|
||||
Memory: 64 * 1024,
|
||||
Iterations: 1,
|
||||
Parallelism: uint8(runtime.NumCPU()),
|
||||
SaltLength: 16,
|
||||
KeyLength: 32,
|
||||
}
|
||||
|
||||
func (p *Argon2params) GeneratePassEncoding(password string) (encoding string, err error) {
|
||||
salt, err := generateRandomBytes(uint(p.SaltLength))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
hash := argon2.IDKey([]byte(password), salt, p.Iterations, p.Memory, p.Parallelism, p.KeyLength)
|
||||
|
||||
// Base64 encode the salt and hashed password.
|
||||
b64Salt := base64.RawStdEncoding.EncodeToString(salt)
|
||||
b64Hash := base64.RawStdEncoding.EncodeToString(hash)
|
||||
|
||||
// Return a string using the standard encoded hash representation.
|
||||
encoding = fmt.Sprintf("$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s", argon2.Version, p.Memory, p.Iterations, p.Parallelism, b64Salt, b64Hash)
|
||||
|
||||
return encoding, nil
|
||||
}
|
||||
|
||||
func CheckPasswordAgainstEncoding(password string, encodedHash string) (match bool, err error) {
|
||||
p, salt, hash, err := decodeHash(encodedHash)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Derive the key from the other password using the same parameters.
|
||||
otherHash := argon2.IDKey([]byte(password), salt, p.Iterations, p.Memory, p.Parallelism, p.KeyLength)
|
||||
|
||||
// Check that the contents of the hashed passwords are identical. Note
|
||||
// that we are using the subtle.ConstantTimeCompare() function for this
|
||||
// to help prevent timing attacks.
|
||||
if subtle.ConstantTimeCompare(hash, otherHash) == 1 {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// PRIVATE STUFF
|
||||
|
||||
// error statements
|
||||
var ErrInvalidHash = errors.New("the encoded hash is not in the correct format")
|
||||
var ErrIncompatibleVersion = errors.New("incompatible version of argon2")
|
||||
|
||||
func decodeHash(encodedHash string) (p *Argon2params, salt []byte, hash []byte, err error) {
|
||||
|
||||
vals := strings.Split(encodedHash, "$")
|
||||
if len(vals) != 6 {
|
||||
return nil, nil, nil, ErrInvalidHash
|
||||
}
|
||||
|
||||
var version int
|
||||
_, err = fmt.Sscanf(vals[2], "v=%d", &version)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if version != argon2.Version {
|
||||
return nil, nil, nil, ErrIncompatibleVersion
|
||||
}
|
||||
|
||||
p = &Argon2params{}
|
||||
_, err = fmt.Sscanf(vals[3], "m=%d,t=%d,p=%d", &p.Memory, &p.Iterations, &p.Parallelism)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
salt, err = base64.RawStdEncoding.Strict().DecodeString(vals[4])
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
p.SaltLength = uint32(len(salt))
|
||||
|
||||
hash, err = base64.RawStdEncoding.Strict().DecodeString(vals[5])
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
p.KeyLength = uint32(len(hash))
|
||||
|
||||
return p, salt, hash, nil
|
||||
|
||||
}
|
||||
|
||||
func generateRandomBytes(saltLen uint) ([]byte, error) {
|
||||
|
||||
var bytes []byte = make([]byte, saltLen)
|
||||
|
||||
_, err := rand.Read(bytes)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bytes, nil
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
module backend/signin
|
||||
|
||||
go 1.24.2
|
||||
|
||||
require (
|
||||
github.com/redis/go-redis/v9 v9.7.3
|
||||
golang.org/x/crypto v0.36.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
)
|
||||
@ -1,14 +0,0 @@
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
||||
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
@ -1,156 +0,0 @@
|
||||
package signin
|
||||
|
||||
import (
|
||||
"backend/redis_helper"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"time"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
// implement a periodic function to clean up the redis database of old tokens
|
||||
|
||||
// Redis related variables
|
||||
const redisDB int = 32
|
||||
|
||||
var redisClient *redis.Client = nil
|
||||
var ctx context.Context = nil
|
||||
|
||||
var SessionTime int = 600 // in seconds -1 is infinity
|
||||
var TokenLength uint = 32
|
||||
|
||||
type SessionCookie struct {
|
||||
token string
|
||||
username string
|
||||
}
|
||||
|
||||
type redisSettings struct {
|
||||
host string
|
||||
port uint16
|
||||
password string
|
||||
db uint64
|
||||
protocol uint64
|
||||
}
|
||||
|
||||
// func processSettingsMap(settings map[string]string, setting_struct *redisSettings) error {
|
||||
// for key, val := range settings {
|
||||
// // fmt.Println(key, val)
|
||||
// if val == "" {
|
||||
// continue
|
||||
// }
|
||||
// switch key {
|
||||
// case "host":
|
||||
// // fmt.Println("entered")
|
||||
// setting_struct.host = val
|
||||
// case "port":
|
||||
// s, err := strconv.ParseUint(val, 10, 16)
|
||||
// if s < 3000 || err != nil {
|
||||
// return ErrInvalidRedisPort
|
||||
// }
|
||||
// setting_struct.port = uint16(s)
|
||||
// case "password":
|
||||
// setting_struct.password = val
|
||||
// case "db":
|
||||
// s, err := strconv.ParseUint(val, 10, 64)
|
||||
// if err != nil {
|
||||
// return ErrInvalidRedisDB
|
||||
// }
|
||||
// setting_struct.db = s
|
||||
// case "protocol":
|
||||
// s, err := strconv.ParseUint(val, 10, 64)
|
||||
// if err != nil {
|
||||
// return ErrInvalidRedisProtocol
|
||||
// }
|
||||
// setting_struct.db = s
|
||||
// }
|
||||
// }
|
||||
// // fmt.Println(setting_struct)
|
||||
// return nil
|
||||
// }
|
||||
|
||||
func generateSecureToken(length uint) (string, error) {
|
||||
|
||||
b, err := generateRandomBytes(length)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(b), nil
|
||||
}
|
||||
|
||||
func CreateSessionToken(username string) (token string, err error) { // generate token here
|
||||
if redisClient == nil {
|
||||
return "", redis_helper.ErrClientNotYetSet
|
||||
}
|
||||
|
||||
token, err = generateSecureToken(TokenLength)
|
||||
|
||||
err = redisClient.Set(ctx, username, token, time.Second*time.Duration(SessionTime)).Err()
|
||||
|
||||
return token, err
|
||||
}
|
||||
|
||||
func ValidateSession(username string, token string) (bool, error) { // check if it's a valid session against the redis database
|
||||
if redisClient == nil {
|
||||
return false, redis_helper.ErrClientNotYetSet
|
||||
}
|
||||
|
||||
val, err := redisClient.Get(ctx, username).Result()
|
||||
if err != nil || val != token {
|
||||
if err == redis.Nil {
|
||||
err = nil // override the error. Just to say it's not an error, but in fact it's not in the database
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, err
|
||||
}
|
||||
|
||||
func InitializeSessionRedis(settings map[string]string) error {
|
||||
|
||||
options, err := redis_helper.ProcessSettingsMap(settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = redis_helper.SetDB(options, redisDB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// initializing redis connection
|
||||
redisClient, err = redis_helper.InitializeRedis(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx = context.Background()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ClearSessions() error {
|
||||
if redisClient == nil {
|
||||
return redis_helper.ErrClientNotYetSet
|
||||
}
|
||||
|
||||
err := redisClient.FlushDB(ctx).Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ClearSession(username string) error {
|
||||
if redisClient == nil {
|
||||
return redis_helper.ErrClientNotYetSet
|
||||
}
|
||||
|
||||
err := redisClient.Del(ctx, username).Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// possibly need something with a csrf token
|
||||
@ -1,65 +0,0 @@
|
||||
package signin
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Login struct {
|
||||
HashedPassword string
|
||||
SessionToken string
|
||||
CSRFToken string
|
||||
}
|
||||
|
||||
var users = map[string]Login{}
|
||||
|
||||
func validUsername(username string) bool {
|
||||
// Implement your logic to check if the username is valid
|
||||
return true
|
||||
}
|
||||
|
||||
func validPassword(password string) bool {
|
||||
// Implement your logic to check if the password is valid
|
||||
return true
|
||||
}
|
||||
|
||||
func login(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
}
|
||||
|
||||
func logout(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func register(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
err := http.StatusMethodNotAllowed
|
||||
http.Error(w, "Invalid method", err)
|
||||
return
|
||||
}
|
||||
|
||||
username := r.FormValue("username")
|
||||
password := r.FormValue("password")
|
||||
|
||||
if !validUsername(username) || !validPassword(password) {
|
||||
err := http.StatusUnauthorized
|
||||
http.Error(w, "Invalid username/password", err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := users[username]; ok { // place holder. actually checks the database
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func test_protected(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Write([]byte("Hello from the protected endpoint!"))
|
||||
}
|
||||
|
||||
func SetupSecurityAddresses() {
|
||||
http.HandleFunc("/login", login)
|
||||
http.HandleFunc("/logout", logout)
|
||||
http.HandleFunc("/register", register)
|
||||
http.HandleFunc("/test-protected", test_protected)
|
||||
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
redis:
|
||||
host: "10.0.20.46"
|
||||
port:
|
||||
password: "banananana"
|
||||
database:
|
||||
address:
|
||||
port:
|
||||
user:
|
||||
password:
|
||||
|
||||
|
||||
3
backend/go.mod
Normal file
3
backend/go.mod
Normal file
@ -0,0 +1,3 @@
|
||||
module git.ewellenr.ca/receipt_indexer/backend
|
||||
|
||||
go 1.24.2
|
||||
15
backend/internal/auth/auth.go
Normal file
15
backend/internal/auth/auth.go
Normal file
@ -0,0 +1,15 @@
|
||||
package auth
|
||||
|
||||
type Authenticator interface {
|
||||
NewUser(username string, password string) error
|
||||
ChangePassword(username string, oldPassword string, newPassword string) error
|
||||
ResetPassword(username string, newPassword string) error // need to enable some sort of authorization stuff
|
||||
DeleteUser(username string, password string) error
|
||||
|
||||
CreateSessionTokens() (token string, regentoken string, err error)
|
||||
RegenSessionTokens(regenToken string) (token string, regentoken string, err error)
|
||||
ValidateToken(token string) error
|
||||
EndSession() error
|
||||
|
||||
// need to figure out the role stuff
|
||||
}
|
||||
130
backend/internal/auth/local_auth.go
Normal file
130
backend/internal/auth/local_auth.go
Normal file
@ -0,0 +1,130 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"git.ewellenr.ca/receipt_indexer/backend/internal/lcrypto"
|
||||
"git.ewellenr.ca/receipt_indexer/backend/internal/storage"
|
||||
)
|
||||
|
||||
type LocalAuth struct {
|
||||
sessStore storage.SessionStore
|
||||
userStore storage.UserStore
|
||||
crypographer lcrypto.Hasher
|
||||
sessionKeyLength uint
|
||||
}
|
||||
|
||||
func generateSessionKey(length uint) (string, error) {
|
||||
key, err := lcrypto.GenerateRandomBytes(length)
|
||||
return string(key), err
|
||||
}
|
||||
|
||||
func (la *LocalAuth) NewUser(username string, password string) (err error) {
|
||||
|
||||
// check for existing user
|
||||
|
||||
}
|
||||
|
||||
func (la *LocalAuth) CreateSessionTokens() (token string, regentoken string, err error) {
|
||||
token, err = generateSessionKey(la.sessionKeyLength)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
err = la.sessStore.AddSession(token)
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// // argon2 parameter struct
|
||||
// type Argon2params struct {
|
||||
// Memory uint32
|
||||
// Iterations uint32
|
||||
// Parallelism uint8
|
||||
// SaltLength uint32
|
||||
// KeyLength uint32
|
||||
// }
|
||||
|
||||
// var DefaultArgon2Params = &Argon2params{
|
||||
// Memory: 64 * 1024,
|
||||
// Iterations: 1,
|
||||
// Parallelism: uint8(runtime.NumCPU()),
|
||||
// SaltLength: 16,
|
||||
// KeyLength: 32,
|
||||
// }
|
||||
|
||||
// func (p *Argon2params) GeneratePassEncoding(password string) (encoding string, err error) {
|
||||
// salt, err := generateRandomBytes(uint(p.SaltLength))
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
|
||||
// hash := argon2.IDKey([]byte(password), salt, p.Iterations, p.Memory, p.Parallelism, p.KeyLength)
|
||||
|
||||
// // Base64 encode the salt and hashed password.
|
||||
// b64Salt := base64.RawStdEncoding.EncodeToString(salt)
|
||||
// b64Hash := base64.RawStdEncoding.EncodeToString(hash)
|
||||
|
||||
// // Return a string using the standard encoded hash representation.
|
||||
// encoding = fmt.Sprintf("$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s", argon2.Version, p.Memory, p.Iterations, p.Parallelism, b64Salt, b64Hash)
|
||||
|
||||
// return encoding, nil
|
||||
// }
|
||||
|
||||
// func CheckPasswordAgainstEncoding(password string, encodedHash string) (match bool, err error) {
|
||||
// p, salt, hash, err := decodeHash(encodedHash)
|
||||
// if err != nil {
|
||||
// return false, err
|
||||
// }
|
||||
|
||||
// // Derive the key from the other password using the same parameters.
|
||||
// otherHash := argon2.IDKey([]byte(password), salt, p.Iterations, p.Memory, p.Parallelism, p.KeyLength)
|
||||
|
||||
// // Check that the contents of the hashed passwords are identical. Note
|
||||
// // that we are using the subtle.ConstantTimeCompare() function for this
|
||||
// // to help prevent timing attacks.
|
||||
// if subtle.ConstantTimeCompare(hash, otherHash) == 1 {
|
||||
// return true, nil
|
||||
// }
|
||||
// return false, nil
|
||||
// }
|
||||
|
||||
// // PRIVATE STUFF
|
||||
|
||||
// // error statements
|
||||
// var ErrInvalidHash = errors.New("the encoded hash is not in the correct format")
|
||||
// var ErrIncompatibleVersion = errors.New("incompatible version of argon2")
|
||||
|
||||
// func decodeHash(encodedHash string) (p *Argon2params, salt []byte, hash []byte, err error) {
|
||||
|
||||
// vals := strings.Split(encodedHash, "$")
|
||||
// if len(vals) != 6 {
|
||||
// return nil, nil, nil, ErrInvalidHash
|
||||
// }
|
||||
|
||||
// var version int
|
||||
// _, err = fmt.Sscanf(vals[2], "v=%d", &version)
|
||||
// if err != nil {
|
||||
// return nil, nil, nil, err
|
||||
// }
|
||||
// if version != argon2.Version {
|
||||
// return nil, nil, nil, ErrIncompatibleVersion
|
||||
// }
|
||||
|
||||
// p = &Argon2params{}
|
||||
// _, err = fmt.Sscanf(vals[3], "m=%d,t=%d,p=%d", &p.Memory, &p.Iterations, &p.Parallelism)
|
||||
// if err != nil {
|
||||
// return nil, nil, nil, err
|
||||
// }
|
||||
|
||||
// salt, err = base64.RawStdEncoding.Strict().DecodeString(vals[4])
|
||||
// if err != nil {
|
||||
// return nil, nil, nil, err
|
||||
// }
|
||||
// p.SaltLength = uint32(len(salt))
|
||||
|
||||
// hash, err = base64.RawStdEncoding.Strict().DecodeString(vals[5])
|
||||
// if err != nil {
|
||||
// return nil, nil, nil, err
|
||||
// }
|
||||
// p.KeyLength = uint32(len(hash))
|
||||
|
||||
// return p, salt, hash, nil
|
||||
|
||||
// }
|
||||
18
backend/internal/env/env.go
vendored
Normal file
18
backend/internal/env/env.go
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package env
|
||||
|
||||
type environment interface {
|
||||
Initialize(path string)
|
||||
GetString(key string, defaultValue string) string
|
||||
GetBool(key string, defaultValue bool) bool
|
||||
GetInt(key string, defaultValue int) int
|
||||
}
|
||||
|
||||
// func GetString(key, fallback string) string {
|
||||
// value, ok := os.LookupEnv(key)
|
||||
// if !ok {
|
||||
// return fallback
|
||||
// }
|
||||
// return value
|
||||
// }
|
||||
|
||||
// repeate for bool and int and such
|
||||
105
backend/internal/lcrypto/lcrypto.go
Normal file
105
backend/internal/lcrypto/lcrypto.go
Normal file
@ -0,0 +1,105 @@
|
||||
package lcrypto
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/argon2"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidHash = errors.New("the encoded hash is not in the correct format")
|
||||
ErrIncompatibleVersion = errors.New("incompatible hash version")
|
||||
ErrWrongHashAlgo = errors.New("wrong hash algorithm")
|
||||
)
|
||||
|
||||
type Hasher interface {
|
||||
CheckPass(pass string, encoded string) (bool, error)
|
||||
hash(pass string) ([]byte, error)
|
||||
Hash(password string) (string, error)
|
||||
}
|
||||
|
||||
type HashAlgo interface {
|
||||
name() string
|
||||
version() uint
|
||||
serialize() ([]byte, error)
|
||||
deserialize(serialization []byte) error
|
||||
}
|
||||
|
||||
func compareHash(h1 []byte, h2 []byte) (bool, error) {
|
||||
if subtle.ConstantTimeCompare(h1, h2) == 1 {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func GenerateRandomBytes(saltLen uint) ([]byte, error) {
|
||||
|
||||
var bytes []byte = make([]byte, saltLen)
|
||||
|
||||
_, err := rand.Read(bytes)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bytes, nil
|
||||
}
|
||||
|
||||
func encodeHashString(hashalgo string, version uint, hash []byte, salt []byte, params HashAlgo) (string, error) {
|
||||
|
||||
// Base64 encode the salt and hashed password.
|
||||
b64Salt := base64.RawStdEncoding.EncodeToString(salt)
|
||||
b64Hash := base64.RawStdEncoding.EncodeToString(hash)
|
||||
paramEncode, err := params.serialize()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
b64Params := base64.RawStdEncoding.EncodeToString(paramEncode)
|
||||
|
||||
encoding := fmt.Sprintf("$%s$v=%d$p=%s$%s$%s", hashalgo, version, b64Params, b64Salt, b64Hash)
|
||||
return encoding, nil
|
||||
}
|
||||
|
||||
func decodeHashString(encodedString string) (encodedHash string, hash []byte, salt []byte, err error) {
|
||||
|
||||
vals := strings.Split(encodedString, "$")
|
||||
if len(vals) != 5 {
|
||||
return "", nil, nil, ErrInvalidHash
|
||||
}
|
||||
|
||||
var version int
|
||||
_, err = fmt.Sscanf(vals[2], "v=%d", &version)
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
}
|
||||
if version != argon2.Version {
|
||||
return nil, nil, nil, ErrIncompatibleVersion
|
||||
}
|
||||
|
||||
p = &Argon2params{}
|
||||
_, err = fmt.Sscanf(vals[3], "m=%d,t=%d,p=%d", &p.Memory, &p.Iterations, &p.Parallelism)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
salt, err = base64.RawStdEncoding.Strict().DecodeString(vals[4])
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
}
|
||||
p.SaltLength = uint32(len(salt))
|
||||
|
||||
hash, err = base64.RawStdEncoding.Strict().DecodeString(vals[5])
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
}
|
||||
p.KeyLength = uint32(len(hash))
|
||||
|
||||
return p, salt, hash, nil
|
||||
|
||||
return "", nil, nil, nil
|
||||
}
|
||||
9
backend/internal/storage/session.go
Normal file
9
backend/internal/storage/session.go
Normal file
@ -0,0 +1,9 @@
|
||||
package storage
|
||||
|
||||
import "time"
|
||||
|
||||
type SessionStore interface {
|
||||
AddSession(sessKey string) error
|
||||
RemoveSession(sessKey string) error
|
||||
SetLifespan(sessKey string, lf time.Time) error
|
||||
}
|
||||
7
backend/internal/storage/user.go
Normal file
7
backend/internal/storage/user.go
Normal file
@ -0,0 +1,7 @@
|
||||
package storage
|
||||
|
||||
type UserStore interface {
|
||||
AddUser(user string, password string) error
|
||||
RemoveUser(user string, password string) error
|
||||
UpdateUserPass(user string, password string) error
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user