From 205d9cf8b036d662766e78317dbf173aadb6a3fe Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Wed, 4 Mar 2026 18:23:00 +0300 Subject: [PATCH] test --- .env | 8 ++-- Dockerfile | 3 +- Makefile | 4 +- app/config.go | 44 +++++++++++++++++ app/database.go | 38 +++++++++++++++ app/provider.go | 108 +++++++++++++---------------------------- app/routes.go | 107 ++++++++++++++++++++++++----------------- app/types.go | 114 ++++++++++++++++++++++++++++++++++++++++++++ app/utils.go | 35 ++++---------- config.yaml | 39 +++++++++++++++ docker-compose.yaml | 13 +++++ go.mod | 16 ++++++- go.sum | 28 +++++++++++ main.go | 36 +++++++++----- scripts/00-init.sql | 11 +++++ 15 files changed, 439 insertions(+), 165 deletions(-) create mode 100644 app/config.go create mode 100644 app/database.go create mode 100644 app/types.go create mode 100644 config.yaml create mode 100644 docker-compose.yaml create mode 100644 scripts/00-init.sql diff --git a/.env b/.env index 46a29b6..061ae86 100644 --- a/.env +++ b/.env @@ -1,6 +1,8 @@ +PSQL_HOST=127.0.0.1 +PSQL_NAME=hyst2 +PSQL_USER=hyst2 +PSQL_PASS=123456 + JWT_SECRET=CHANGEME -HOST=127.0.0.1 -PORT=443 -OBFS_PASSWORD=test SNI=vk.com NAME_FORMAT={username} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index de61d37..6d4c7be 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,4 +10,5 @@ FROM alpine:3.23 AS runner WORKDIR /app COPY --from=builder /src/api /app/api EXPOSE 8080 -CMD ["/app/api"] \ No newline at end of file +CMD ["/app/api"] +USER nobody \ No newline at end of file diff --git a/Makefile b/Makefile index c70377c..c2dacdd 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,3 @@ build: - docker build -t git.nix13.pw/scuroneko/h2auth:latest . - docker push git.nix13.pw/scuroneko/h2auth:latest \ No newline at end of file + docker build -t git.nix13.pw/scuroneko/h2node:latest . + docker push git.nix13.pw/scuroneko/h2node:latest \ No newline at end of file diff --git a/app/config.go b/app/config.go new file mode 100644 index 0000000..e6db322 --- /dev/null +++ b/app/config.go @@ -0,0 +1,44 @@ +package app + +import ( + "io" + "log" + "os" + + "gopkg.in/yaml.v3" +) + +type Config struct { + JWTSecret string + Host string + SNI string + NameFormat string +} + +var cfg *Config +var hysteriaCfg *HysteriaConfig + +func LoadConfig() { + cfg = &Config{ + JWTSecret: os.Getenv("JWT_SECRET"), + Host: LoadIP(), + SNI: os.Getenv("SNI"), + NameFormat: os.Getenv("NAME_FORMAT"), + } + hysteriaCfg = &HysteriaConfig{} + + f, err := os.Open("config.yaml") + if err != nil { + panic(err) + } + defer f.Close() + data, err := io.ReadAll(f) + if err != nil { + panic(err) + } + err = yaml.Unmarshal(data, hysteriaCfg) + if err != nil { + panic(err) + } + log.Println(cfg, hysteriaCfg) +} diff --git a/app/database.go b/app/database.go new file mode 100644 index 0000000..7f60cd6 --- /dev/null +++ b/app/database.go @@ -0,0 +1,38 @@ +package app + +import ( + "fmt" + "os" + + "github.com/vinovest/sqlx" +) +import _ "github.com/lib/pq" + +var db *sqlx.DB = nil + +func init() { + if db == nil { + connectPsql() + } +} + +func getDSN() string { + user := os.Getenv("PSQL_USER") + password := os.Getenv("PSQL_PASS") + database := os.Getenv("PSQL_NAME") + host, exists := os.LookupEnv("PSQL_HOST") + if !exists { + host = "localhost" + } + return fmt.Sprintf("postgresql://%s:%s@%s/%s?sslmode=disable", user, password, host, database) +} +func connectPsql() { + var err error + db, err = sqlx.Connect("postgres", getDSN()) + if err != nil { + panic(err) + } +} +func ClosePsql() error { + return db.Close() +} diff --git a/app/provider.go b/app/provider.go index 24e56ba..9007fbd 100644 --- a/app/provider.go +++ b/app/provider.go @@ -1,9 +1,7 @@ package app import ( - "encoding/json" - "errors" - "os" + "github.com/vinovest/sqlx" ) type User struct { @@ -11,86 +9,46 @@ type User struct { Username string `json:"username"` Password string `json:"password"` } -type Provider struct { - Users []User `json:"users"` - LastUserID int `json:"last_user_id"` - path string +type UserUsage struct { + UserID int `json:"user_id" db:"user_id"` + Recv int64 `json:"recv" db:"recv"` + Sent int64 `json:"sent" db:"sent"` } -// NewProvider создаёт новый провайдер с пустыми данными (файл не трогает) -func NewProvider() *Provider { - return &Provider{ - Users: make([]User, 0), - LastUserID: 0, - path: "./provider.json", - } +type UserRepository struct { + db *sqlx.DB } -// LoadProvider загружает данные из файла, если файла нет — возвращает новый провайдер -func LoadProvider() (*Provider, error) { - data, err := os.ReadFile("./provider.json") - if err != nil { - if os.IsNotExist(err) { - // файл не существует, возвращаем новый провайдер - return NewProvider(), nil - } - return nil, err - } - - p := &Provider{path: "./provider.json"} - if err := json.Unmarshal(data, p); err != nil { - return nil, err - } - return p, nil +func NewUserRepository(db *sqlx.DB) *UserRepository { + return &UserRepository{db} } -// Save сохраняет текущее состояние в файл -func (p *Provider) Save() error { - data, err := json.MarshalIndent(p, "", " ") // для читаемости - if err != nil { - return err - } - return os.WriteFile(p.path, data, 0644) +func (rep UserRepository) AddUser(username, password string) (User, error) { + sql := "INSERT INTO users (username, password) VALUES (?, ?) RETURNING *;" + sql = rep.db.Rebind(sql) + var user User + err := db.Get(&user, sql, username, password) + return user, err } -func (p *Provider) AddUser(username, password string) error { - p.LastUserID++ - p.Users = append(p.Users, User{ - ID: p.LastUserID, - Username: username, - Password: password, - }) - return p.Save() +func (rep UserRepository) GetById(id int) (User, error) { + var user User + sql := "SELECT * FROM users WHERE id=?;" + sql = rep.db.Rebind(sql) + err := rep.db.Get(&user, sql, id) + return user, err +} +func (rep UserRepository) GetUsers() ([]User, error) { + users := make([]User, 0) + sql := "SELECT * FROM users;" + sql = rep.db.Rebind(sql) + err := rep.db.Select(&users, sql) + return users, err } -func (p *Provider) GetById(id int) (User, error) { - for _, user := range p.Users { - if user.ID == id { - return user, nil - } - } - return User{}, errors.New("user not found") -} -func (p *Provider) GetUser(password string) (User, error) { - for _, user := range p.Users { - if user.Password == password { - return user, nil - } - } - return User{}, errors.New("user not found") -} - -func (p *Provider) DeleteUser(id int) error { - index := -1 - for i, user := range p.Users { - if user.ID == id { - index = i - break - } - } - if index == -1 { - return errors.New("user not found") - } - p.Users = append(p.Users[:index], p.Users[index+1:]...) - return p.Save() +func (rep UserRepository) DeleteUser(id int) error { + sql := "DELETE FROM users WHERE id=?;" + sql = rep.db.Rebind(sql) + _, err := rep.db.Exec(sql, id) + return err } diff --git a/app/routes.go b/app/routes.go index 28f1331..8409ea7 100644 --- a/app/routes.go +++ b/app/routes.go @@ -1,12 +1,17 @@ package app import ( + "database/sql" + "encoding/base64" "encoding/json" "errors" "fmt" "io" "log" "net/http" + "strconv" + + "github.com/go-chi/chi/v5" ) type AddUserReq struct { @@ -31,22 +36,8 @@ func AddUser(w http.ResponseWriter, r *http.Request) { return } - provider, err := LoadProvider() - if err != nil { - WriteError(w, err) - return - } - err = provider.AddUser(req.Username, req.Password) - if err != nil { - WriteError(w, err) - return - } - err = provider.Save() - if err != nil { - WriteError(w, err) - } - - user, err := provider.GetUser(req.Password) + rep := NewUserRepository(db) + user, err := rep.AddUser(req.Username, req.Password) if err != nil { WriteError(w, err) return @@ -69,17 +60,8 @@ func DeleteUser(w http.ResponseWriter, r *http.Request) { return } - provider, err := LoadProvider() - if err != nil { - WriteError(w, err) - return - } - err = provider.DeleteUser(req.ID) - if err != nil { - WriteError(w, err) - return - } - err = provider.Save() + rep := NewUserRepository(db) + err = rep.DeleteUser(req.ID) if err != nil { WriteError(w, err) return @@ -94,12 +76,13 @@ func AllUsers(w http.ResponseWriter, r *http.Request) { return } - provider, err := LoadProvider() + rep := NewUserRepository(db) + users, err := rep.GetUsers() if err != nil { WriteError(w, err) return } - WriteResponse(w, provider) + WriteResponse(w, users) } type GetConnectURLReq struct { @@ -114,25 +97,58 @@ func GetUserURL(w http.ResponseWriter, r *http.Request) { return } - provider, err := LoadProvider() + rep := NewUserRepository(db) + user, err := rep.GetById(req.ID) if err != nil { WriteError(w, err) return } - user, err := provider.GetById(req.ID) + //if user.Password != req.Pass { + // WriteError(w, errors.New("invalid password")) + // return + //} + + urlTemplate := "hysteria2://%s@%s%s?obfs=salamander&obfs-password=%s&type=hysteria&mport&security=tls&sni=%s&alpn=h3&fp=chrome&allowInsecure=0#%s" + authString := encodeURL(user) + u := fmt.Sprintf( + urlTemplate, + authString, + cfg.Host, + hysteriaCfg.Listen, + hysteriaCfg.Obfs.Salamander.Password, + cfg.SNI, + formatConfigName(cfg.NameFormat, user), + ) + WriteResponse(w, u) +} + +func Sub(w http.ResponseWriter, r *http.Request) { + idS := chi.URLParam(r, "id") + id, err := strconv.Atoi(idS) if err != nil { WriteError(w, err) return } - if user.Password != req.Pass { - WriteError(w, errors.New("invalid password")) - return - } - urlTemplate := "hysteria2://%s@%s:%s?obfs=salamander&obfs-password=%s&type=hysteria&mport&security=tls&sni=%s&alpn=h3&fp=chrome&allowInsecure=0#%s" + rep := NewUserRepository(db) + user, err := rep.GetById(id) + if err != nil { + WriteError(w, err) + return + } + + urlTemplate := "hysteria2://%s@%s%s?obfs=salamander&obfs-password=%s&type=hysteria&mport&security=tls&sni=%s&alpn=h3&fp=chrome&allowInsecure=0#%s" authString := encodeURL(user) - u := fmt.Sprintf(urlTemplate, authString, cfg.Host, cfg.Port, cfg.ObfsPassword, cfg.SNI, formatConfigName(cfg.NameFormat, user)) - WriteResponse(w, u) + u := fmt.Sprintf( + urlTemplate, + authString, + cfg.Host, + hysteriaCfg.Listen, + hysteriaCfg.Obfs.Salamander.Password, + cfg.SNI, + formatConfigName(cfg.NameFormat, user), + ) + w.Write([]byte(base64.StdEncoding.EncodeToString([]byte(u)))) } type AuthReq struct { @@ -154,7 +170,7 @@ func DoAuth(w http.ResponseWriter, r *http.Request) { } req := new(AuthReq) - if err := json.Unmarshal(data, req); err != nil { + if err = json.Unmarshal(data, req); err != nil { w.WriteHeader(http.StatusBadRequest) log.Println(err) return @@ -164,20 +180,21 @@ func DoAuth(w http.ResponseWriter, r *http.Request) { reqUser, err := decodeURL(req.Auth) if err != nil { w.WriteHeader(http.StatusBadRequest) + log.Println(err) return } - provider, err := LoadProvider() + rep := NewUserRepository(db) + user, err := rep.GetById(reqUser.ID) if err != nil { + if errors.Is(err, sql.ErrNoRows) { + w.WriteHeader(http.StatusNotFound) + return + } log.Println(err) w.WriteHeader(http.StatusBadRequest) return } - user, err := provider.GetUser(reqUser.Password) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - return - } res := &AuthRsp{true, user.Username} err = json.NewEncoder(w).Encode(res) diff --git a/app/types.go b/app/types.go new file mode 100644 index 0000000..89df47d --- /dev/null +++ b/app/types.go @@ -0,0 +1,114 @@ +package app + +type HysteriaTLSConfig struct { + Cert string `yaml:"cert"` + Key string `yaml:"key"` +} + +type HysteriaObfsConfig struct { + Type string `yaml:"type"` + Salamander struct { + Password string `yaml:"password"` + } `yaml:"salamander"` +} + +type HysteriaQuicConfig struct { + InitStreamReceiveWindow *int64 `yaml:"initStreamReceiveWindow"` + MaxStreamReceiveWindow *int64 `yaml:"maxStreamReceiveWindow"` + InitConnReceiveWindow *int64 `yaml:"initConnReceiveWindow"` + MaxConnReceiveWindow *int64 `yaml:"maxConnReceiveWindow"` + MaxIdleTimeout *string `yaml:"maxIdleTimeout"` + MaxIncomingStream *int64 `yaml:"maxIncomingStream"` + DisablePathMTUDiscovery *bool `yaml:"disablePathMTUDiscovery"` +} + +type HysteriaBandwidthConfig struct { + UP *string `yaml:"up"` + Down *string `yaml:"down"` + IgnoreClientBandwidth *bool `yaml:"ignoreClientBandwidth"` +} + +type HysteriaAuthType string +type HysteriaAuthConfig struct { + Type HysteriaAuthType `yaml:"type"` + Password string `yaml:"password,omitempty"` + Userpass map[string]string `yaml:"userpass,omitempty"` + Http struct { + URL string `yaml:"url"` + Insecure bool `yaml:"insecure"` + } `yaml:"http,omitempty"` + Command string `yaml:"command,omitempty"` +} + +type HysteriaTCPUDPResolverConfig struct { + Address string `yaml:"addr"` + Timeout string `yaml:"timeout"` +} +type HysteriaTLSResolverConfig struct { + Address string `yaml:"addr"` + Timeout string `yaml:"timeout"` + SNI string `yaml:"sni"` + Insecure bool `yaml:"insecure"` +} +type HysteriaResolverType string +type HysteriaResolverConfig struct { + Type HysteriaResolverType `yaml:"type"` + TCP *HysteriaTCPUDPResolverConfig `yaml:"tcp,omitempty"` + UDP *HysteriaTCPUDPResolverConfig `yaml:"udp,omitempty"` + TLS *HysteriaTLSResolverConfig `yaml:"tls,omitempty"` + HTTPS *HysteriaTLSResolverConfig `yaml:"https,omitempty"` +} + +type HysteriaSniffConfig struct { + Enable bool `yaml:"enable"` +} + +type HysteriaACLConfig struct{} +type HysteriaOutboundConfig struct { + Name string `yaml:"name"` + Type string `yaml:"type"` +} + +type HysteriaTrafficStatsConfig struct { + Listen string `yaml:"listen"` + Secret string `yaml:"secret"` +} + +type HysteriaMasqueradeType string +type HysteriaMasqueradeFile struct { + Dir string `yaml:"dir"` +} +type HysteriaMasqueradeProxy struct { + URL string `yaml:"url"` + RewriteHost *bool `yaml:"rewriteHost,omitempty"` + Insecure *bool `yaml:"insecure,omitempty"` +} +type HysteriaMasqueradeString struct { + Content string `yaml:"content"` + Headers map[string]string `yaml:"headers,omitempty"` + StatusCode int `yaml:"statusCode"` +} +type HysteriaMasqueradeConfig struct { + Type HysteriaMasqueradeType `yaml:"type"` + File *HysteriaMasqueradeFile `yaml:"file,omitempty"` + Proxy *HysteriaMasqueradeProxy `yaml:"proxy,omitempty"` + String *HysteriaMasqueradeString `yaml:"string,omitempty"` + + ListenHTTP *string `yaml:"listenHTTP,omitempty"` + ListenHTTPS *string `yaml:"listenHTTPS,omitempty"` + ForceHTTPS *bool `yaml:"forceHTTPS,omitempty"` +} + +type HysteriaConfig struct { + Listen string `yaml:"listen"` + TLS HysteriaTLSConfig `yaml:"tls"` + Obfs *HysteriaObfsConfig `yaml:"obfs,omitempty"` + Quic *HysteriaQuicConfig `yaml:"quic,omitempty"` + SpeedTest *bool `yaml:"speedTest,omitempty"` + Auth HysteriaAuthConfig `yaml:"auth"` + Resolver *HysteriaResolverConfig `yaml:"resolver,omitempty"` + Sniff *HysteriaSniffConfig `yaml:"sniff,omitempty"` + ACL *HysteriaACLConfig `yaml:"acl,omitempty"` + Outbounds []HysteriaOutboundConfig `yaml:"outbounds,omitempty"` + TrafficStats *HysteriaTrafficStatsConfig `yaml:"trafficStats,omitempty"` +} diff --git a/app/utils.go b/app/utils.go index 5905485..487cb04 100644 --- a/app/utils.go +++ b/app/utils.go @@ -4,7 +4,6 @@ import ( "encoding/base64" "fmt" "io" - "log" "net/http" "os" "strings" @@ -47,31 +46,9 @@ func decodeURL(tokenString string) (User, error) { return zero, nil } -type Config struct { - JWTSecret string - Host string - Port string - ObfsPassword string - SNI string - NameFormat string -} - -var cfg *Config - -func LoadConfig() { - cfg = &Config{ - JWTSecret: os.Getenv("JWT_SECRET"), - Host: os.Getenv("HOST"), - Port: os.Getenv("PORT"), - ObfsPassword: os.Getenv("OBFS_PASSWORD"), - SNI: os.Getenv("SNI"), - NameFormat: os.Getenv("NAME_FORMAT"), - } -} - var ip string -func LoadIP() { +func LoadIP() string { res, err := http.Get("https://api.ipify.org") if err != nil { panic(err) @@ -82,10 +59,18 @@ func LoadIP() { panic(err) } ip = string(data) - log.Println(ip) + return ip } func formatConfigName(format string, user User) string { s := strings.ReplaceAll(format, "{username}", user.Username) s = strings.ReplaceAll(s, "{host}", ip) return s } + +func Ptr[T any](t T) *T { return &t } +func Val[T any](t *T, def T) T { + if t == nil { + return def + } + return *t +} diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..7db1be7 --- /dev/null +++ b/config.yaml @@ -0,0 +1,39 @@ +listen: :51052 +tls: + cert: /tls/nix13.pw.crt + key: /tls/nix13.pw.key +auth: + type: http + http: + url: http://h2auth:8080/auth + insecure: false +trafficStats: + listen: :9998 + secret: some_secret +obfs: + type: salamander + salamander: + password: test +masquerade: + type: proxy + proxy: + url: https://news.ycombinator.com/ + rewriteHost: true +resolver: + type: udp + tcp: + addr: 1.1.1.1:53 + timeout: 4s + udp: + addr: 1.1.1.1:53 + timeout: 4s + tls: + addr: 1.1.1.1:853 + timeout: 10s + sni: cloudflare-dns.com + insecure: false + https: + addr: 1.1.1.1:443 + timeout: 10s + sni: cloudflare-dns.com + insecure: false \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..8bf7381 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,13 @@ +services: + psql: + image: postgres:18.2-alpine3.23 + ports: + - "5432:5432" + environment: + POSTGRES_DB: ${PSQL_NAME} + POSTGRES_USER: ${PSQL_USER} + POSTGRES_PASSWORD: ${PSQL_PASS} + volumes: + - postgres_data:/var/lib/postgresql/data +volumes: + postgres_data: \ No newline at end of file diff --git a/go.mod b/go.mod index d0afb53..c285700 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,17 @@ -module Hyst2Auth +module Hyst2Node go 1.26 -require github.com/golang-jwt/jwt/v5 v5.3.1 // indirect +require ( + github.com/go-chi/chi/v5 v5.2.5 + github.com/golang-jwt/jwt/v5 v5.3.1 + github.com/lib/pq v1.11.2 + github.com/vinovest/sqlx v1.7.2 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + github.com/joho/godotenv v1.5.1 // indirect + github.com/muir/list v1.2.1 // indirect + github.com/muir/sqltoken v0.4.0 // indirect +) diff --git a/go.sum b/go.sum index c0f7290..817a623 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,30 @@ +filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw= +filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +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/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-sql-driver/mysql v1.9.0 h1:Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1vtvo= +github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/lib/pq v1.11.2 h1:x6gxUeu39V0BHZiugWe8LXZYZ+Utk7hSJGThs8sdzfs= +github.com/lib/pq v1.11.2/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/muir/list v1.2.1 h1:lmF8fz2B1WbXkzHr/Eh0oWPJArDBzWqIifOwbA4gWSo= +github.com/muir/list v1.2.1/go.mod h1:v0l2f997MxCohQlD7PTejJqyYKwFVz/i3mTpDl4LAf0= +github.com/muir/sqltoken v0.4.0 h1:gBcpeTcy9LxuLZ1PJypGs6zG1/emVmuOPYR7saKbPyk= +github.com/muir/sqltoken v0.4.0/go.mod h1:+OSmbGI22QcVZ6DCzlHT8EAzEq/mqtqedtPP91Le+3A= +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/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/vinovest/sqlx v1.7.2 h1:t/IahCJqO71GJYnhOcACiUXlMiiMomMHtxtUthdcBfo= +github.com/vinovest/sqlx v1.7.2/go.mod h1:o49uG4W/ZYZompljKx5GZ7qx6OFklPjSHXP63nSmND8= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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= diff --git a/main.go b/main.go index 900fb18..5a9ec75 100644 --- a/main.go +++ b/main.go @@ -1,28 +1,40 @@ package main import ( - "Hyst2Auth/app" + "Hyst2Node/app" "log" "net/http" + "time" + + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" + "github.com/joho/godotenv" ) func main() { - app.LoadIP() - app.LoadConfig() - _, err := app.LoadProvider() - if err != nil { - panic(err) + if err := godotenv.Load(".env"); err != nil { + log.Println("Error loading .env file. If you use docker, then you can ignore this.") } - r := http.NewServeMux() - r.HandleFunc("/add", app.AddUser) - r.HandleFunc("/delete", app.DeleteUser) - r.HandleFunc("/users", app.AllUsers) + app.LoadConfig() - r.HandleFunc("/connect", app.GetUserURL) + r := chi.NewRouter() + r.Use(middleware.RequestID) + r.Use(middleware.RealIP) + r.Use(middleware.Logger) + r.Use(middleware.Recoverer) + r.Use(middleware.Timeout(60 * time.Second)) - r.HandleFunc("/auth", app.DoAuth) + r.Post("/add", app.AddUser) + r.Post("/delete", app.DeleteUser) + r.Get("/users", app.AllUsers) + r.Post("/connect", app.GetUserURL) + r.Get("/sub/{id}", app.Sub) + + r.Post("/auth", app.DoAuth) + + defer app.ClosePsql() log.Println("Listening on :8080") if err := http.ListenAndServe(":8080", r); err != nil { log.Fatal(err) diff --git a/scripts/00-init.sql b/scripts/00-init.sql new file mode 100644 index 0000000..f1bf1c4 --- /dev/null +++ b/scripts/00-init.sql @@ -0,0 +1,11 @@ +CREATE TABLE users ( + id SERIAL PRIMARY KEY, + username TEXT NOT NULL, + password TEXT NOT NULL +); +CREATE UNIQUE INDEX users_uindex ON users(id); +CREATE TABLE user_usage( + user_id INT REFERENCES users(id), + recv INT8 NOT NULL DEFAULT 0, + sent INT8 NOT NULL DEFAULT 0 +); \ No newline at end of file